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 пустым, как уже говорили другие.