javascript #reactjs
#javascript #reactjs
Вопрос:
Мой эффект использования — получение данных из веб-api. Я хочу отображать все сообщения на домашней странице и снова запускать мой useEffect, когда кто-то создает новое сообщение. Проблема в том, что когда я ставлю зависимость от useEffect, он начинает выполнять бесконечные запросы. Когда я передаю пустой массив как зависимость, когда кто-то создает новое сообщение, оно не отображается на домашней странице, пока я не обновлю страницу. Я много читал в Интернете об этой проблеме, но все же я не знаю, как это сделать. Спасибо
function App() {
const [posts, setPosts] = useState([]);
useEffect(() => {
const jwt = localStorage.getItem("jwt");
fetch('https://localhost:44366/api/Posts/getAllPosts',
{
method: "GET",
headers: {
"Content-Type": "application/json",
'Authorization': 'Bearer ' jwt
},
})
.then(r => r.json()).then(result => setPosts(result));
}, [posts]);
return (
<div >
<Router>
<Header />
<main className="App">
{
posts.map(post => (
<Post keyToAppend={post.CreatedOn} username={post.User.FirstName} title={post.Title} content={post.Content} images={post.ImageUrls} avatarImage={post.User.MainImageUrl} />
))
}
</main>
</Router>
<Footer />
</div>
);
}
Post-компонент :
const Post = ({ keyToAppend, username, title, content, images, avatarImage }) => {
return (
<div className="post" key={keyToAppend}>
<div className="post__header">
<Avatar
className="post__avatar"
alt="avatar"
src={avatarImage}
/>
<h3 className="username">{username}</h3>
</div>
<h1 className="title">{title}</h1>
<p className="content">{content}</p>
<p>
{typeof images != "undefined" ? <ImageSlider slides={images} /> : ""}
</p>
</div>
)
}
export default Post;
Ответ №1:
Удалить posts
из массива зависимостей, так что это просто []
. Это приведет к запуску эффекта один раз, при загрузке компонента.
useEffect(() => {
const jwt = localStorage.getItem("jwt");
fetch('https://localhost:44366/api/Posts/getAllPosts',
{
method: "GET",
headers: {
"Content-Type": "application/json",
'Authorization': 'Bearer ' jwt
},
})
.then(r => r.json()).then(result => setPosts(result));
}, []);
// ^^−−−−− remove `posts` here
Причина, по которой он выполняется бесконечно с вашим текущим кодом, заключается в том, что ваш обратный вызов effect изменяет элемент posts
состояния, который снова запускает эффект (потому posts
что находится в массиве зависимостей).
Вам нужно только включить элементы в массив зависимостей, которые вы прочитали при обратном вызове эффекта. Вы никогда не читаете posts
обратный вызов эффекта.
Примечание: этот код становится жертвой fetch
API footgun, который я описываю здесь. Перед вызовом необходимо проверить r.ok
r.json
(и обработать ошибки):
useEffect(() => {
const jwt = localStorage.getItem("jwt");
fetch("https://localhost:44366/api/Posts/getAllPosts", {
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " jwt
},
})
.then(r => {
if (!r.ok) { // <=================
throw new Error(`HTTP error ${r.status}`);
}
return r.json();
})
.then(result => setPosts(result))
.catch(error => {
// ...handle/report error here...
});
}, []);
Комментарии:
1. Я понимаю все, что вы сказали, кроме «Вам нужно только включить в массив зависимостей вещи, которые вы прочитали в обратном вызове эффекта».. Мне нужно включить в реквизит массива зависимостей, который получает Post component или? Извините, но все равно не понимаю.
2. @koceww — в обратном вызове ничего не используется
posts
, поэтому вы не должны указыватьposts
в массиве зависимостей. Подробнее: reactjs.org/docs/hooks-reference.html#useeffect