简体   繁体   中英

React useEffect does infinite loop

My useEffect is getting data from web api. I want to render all posts on home page and trigger again my useEffect when someone create new post. The problem is when I put dependancy on useEffect its start doing endless requests. When I pass empty array as dependancy, when someone create new post it doesnt render on home page until I refresh the page. I read a lot in internet about that problem but still I dont know how to do it. Thanks

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 component:

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;

Remove posts from the dependency array, so it's just [] . That will run the effect once, when the component loads.

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

The reason it runs endlessly with your current code is that your effect callback changes the posts state member, which triggers the effect again (because posts is in the dependency array). You only need to include things in the dependency array that you read in the effect callback. You never read posts in the effect callback.


Side note: That code is falling prey to the fetch API footgun I describe here . You need to check r.ok before calling r.json (and handle errors):

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...
    });
}, []);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM