UseEffect вызывает бесконечный цикл, но я не могу найти причину. Также, что я могу улучшить в коде

Я сделал базовый блог как проект с django rest api и react во фронтенде, но useEffect вызывает бесконечный цикл, но я не могу найти причину. Я знаю, что это useEffect, потому что это происходило несколько раз до этого при создании этого проекта, но я смог исправить это, но теперь это было немного трудно. Также побочный вопрос, что вы, ребята, думаете о коде, любые советы или рекомендации будут оценены по достоинству, спасибо.

вы запускаете функцию useEffect при изменении состояния posts, а затем переходите к обновлению состояния в функции useEffect.

лучшее решение:

useEffect(async () => {
    const response = await fetch('http://127.0.0.1:8000/api/post-list/')
    setPosts(await response.json())
  }, [])

это позволит убедиться, что useEffect выполняется только один раз

Уберите посты в массиве зависимостей и сделайте его просто [].

Вот что вам нужно сделать

useEffect(async () => {
    const response = await fetch('http://127.0.0.1:8000/api/post-list/')
    setPosts(await response.json())
  }, [])

Функция внутри useEffect будет выполняться каждый раз при обновлении значения зависимости. Вы добавили posts зависимость useEffect и обновили значение posts внутри эффекта с помощью setPosts. И это вызывает бесконечный цикл.

Просто удалите posts из массива зависимостей.

useEffect(async () => {
  const response = await fetch('http://127.0.0.1:8000/api/post-list/')
  setPosts(await response.json())
}, [])
useEffect(async () => {
    const response = await fetch('http://127.0.0.1:8000/api/post-list/')
    setPosts(await response.json())
}, [posts])

Имея posts в качестве зависимости, это означает, что useEffect callback будет запускаться каждый раз, когда обновляется posts. Обновляя posts в callback, вы вызываете бесконечный цикл. Чтобы избежать этого, вы можете либо удалить posts из массива зависимостей.

Не стоит вызывать ваш API для всего списка каждый раз, когда вы добавляете одну запись в список. У вас уже загружена большая часть данных, поэтому лучше сделать следующее в вашей функции handleSubmit:

    fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(create)
    })
    .then(() => {
      setPosts([...posts, create]);
      setCreate({
        title: "",
        description: "",
        completed: false
      });
    })

Вы добавляете данные из объекта create к уже загруженному массиву posts.

Это проблема бесконечного цикла

Проблема здесь в том, что вы запускаете функцию setPosts внутри useEffect и запускаете хук useEffect, когда значение posts меняется. Поскольку функция setPosts изменяет значение posts, именно это и вызывает цикл:

SetPosts trigger=> posts trigger=>UseEffect trigger=> SetPosts и цикл продолжается.

Лучший способ - удалить посты из хука UseEffect, или найти другую зависимость для хука UseEffect, как показано ниже;

  useEffect(async () => {
    const response = await fetch('http://127.0.0.1:8000/api/post-list/')
    setPosts(await response.json())
  }, [])

Когда вы обновляете посты с помощью setPosts, это снова приводит к выполнению useEffect(). Второй аргумент, который вы передаете useEffect, говорит ему выполнять ваш метод при каждом обновлении [posts], так что когда вы вызываете setPosts(await response.json()) posts обновляется и ваш метод выполняется.

Вы можете предотвратить это с помощью простого оператора if:

useEffect(async () => {
    if(posts.length == 0) {
        const response = await fetch('http://127.0.0.1:8000/api/post-list/')
        setPosts(await response.json())
    }
}, [posts])

В приведенном выше коде fetch и последующий setPosts будут выполняться только тогда, когда длина массива posts равна нулю, если вы выполнили fetch и заполнили posts 1 или более элементами, то useEffect все равно сработает, но не выполнит fetch.

Для иллюстрации этого включите второе значение состояния postsFetched и установите его в true, как только вы получите посты, это предотвратит выполнение вашего метода, предоставленного useEffect, в первую очередь. Что-то вроде:

const [posts, setPosts] = useState([]);
const [postsFetched, setPostsFetched] = useState(false);
...
useEffect(async () => {
    const response = await fetch('http://127.0.0.1:8000/api/post-list/')
    setPosts(await response.json())
    // NOTE: you probably want to qualify that you have fetched posts at this point
    setPostsFetched(true);
}, [postsFetched])

Как сказано в моем комментарии во втором фрагменте, вы можете убедиться, что вы действительно получили несколько сообщений, прежде чем установить postsFetched в true, проверив возврат из await response.json()

Вот некоторые дополнительные материалы для чтения:

Или вы можете просто оставить массив зависимостей useEffect пустым, как уже говорили другие.
Вернуться на верх