@HalvinBRO

Как исправить ошибку при удалении элемента списка?

Доброго времени суток!
Столкнулся с ошибкой, появляющейся в консоли после удаления элемента списка из массива:
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
in Note (at Table.js:14)


Как это исправить? Понимаю, что это как-то связано с преждевременным размонтированием компонента перед завершением api запроса.

Вот код задействованных компонентов:
1. App.js, где рендерится список:
import React, { useState } from "react";
import { api } from "../utils/api";
import Table from "./Table";

function App() {
  const [notes, setNotes] = useState([]);
  const [isLoad, setIsLoad] = useState(false);

  // Рендер записей с сервера
  React.useEffect(() => {
    api
      .getRecords()
      .then((recordsData) => {
        setNotes(recordsData);
      })
      .catch((err) => {
        console.log(err);
      });
  }, []);

  // Добавление записи в таблицу
  function addNewNote(newData) {
    setIsLoad(true);

    const newRecord = {
      data: newData,
    };

    api
      .putRecords(newRecord)
      .then((res) => {
        setNotes([...notes, res]);
      })
      .catch((err) => {
        console.log(err);
      })
      .finally(() => {
        setIsLoad(false);
      });
  }

  return (
    <Table
      notes={notes}
      setNotes={setNotes}
      onAddNewNote={addNewNote}
      isLoad={isLoad}
    />
  );
}

export default App;


2. Table.js, в который я прокидываю полученный массив для его отображения на странице:
import React from "react";
import Note from "./Note";
import NewNote from "./NewNote";

function Table({ notes, onAddNewNote, isLoad, setNotes }) {
  return (
    <div className="table">
      <h1 className="table__title">Таблица CRUD</h1>
      <div className="table__add-area">
        <NewNote handleNewNote={onAddNewNote} isLoad={isLoad} />
      </div>
      <div className="table__list">
        {notes.map((note, i) => (
          <Note
            key={note._id}
            dataNote={note}
            notes={notes}
            setNotes={setNotes}
          />
        ))}
      </div>
    </div>
  );
}

export default Table;


3. Note.js - компонент, необходимый для отображения самого элемента массива:
import React, { useState } from "react";
import { api } from "../utils/api";
import NoteTextArea from "./NoteTextArea";

function Note({ dataNote, notes, setNotes }) {
  const [isEdit, setIsEdit] = useState(false);
  const [isLoaded, setIsLoaded] = useState(false);
  const [isDeleted, setIsDeleted] = useState(false);
  const [note, setNote] = useState({
    name: dataNote.data.name,
    age: dataNote.data.age,
    email: dataNote.data.email,
    phone: dataNote.data.phone,
  });

  function onCardClickEdit() {
    setIsEdit(true);
  }

  function handleChange(e) {
    const { name, value } = e.target;
    setNote((note) => ({
      ...note,
      [name]: value,
    }));
  }

  // Редактирование записи
  function editNote() {
    setIsLoaded(true);

    api
      .editRecord(dataNote._id, note)
      .then(() => {
        setIsEdit(false);
      })
      .catch((err) => {
        console.log(err);
      })
      .finally(() => {
        setIsLoaded(false);
      });
  }

  // Удаление записи из таблицы
  function removeNote() {
    setIsDeleted(true);

    api
      .deleteRecord(dataNote._id)
      .then(() => {
        setNotes(notes.filter((n) => n._id !== dataNote._id));
      })
      .catch((err) => {
        console.log(err);
      })
      .finally(() => {
        setIsDeleted(false);
      });
  }

  return (
    <NoteTextArea
      dataNote={dataNote}
      isEdit={isEdit}
      isLoaded={isLoaded}
      note={note}
      onCardClickEdit={onCardClickEdit}
      handleChange={handleChange}
      deleteNote={removeNote}
      editNote={editNote}
      isDeleted={isDeleted}
    />
  );
}

export default Note;
  • Вопрос задан
  • 32 просмотра
Решения вопроса 1
0xD34F
@0xD34F
Самый простой способ - перенести вызов setIsDeleted из finally в catch.

Понимаю, что это как-то связано с преждевременным размонтированием компонента перед завершением api запроса.

Не связано. Запрос успешно завершается, удаляется элемент данных, соответствующий ему экземпляр компонента тоже долой - и уже после этого вы пытаетесь обновить состояние экземпляра компонента. А зачем? Не всё ли равно, как он будет выглядеть, если его уже нет?
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы