简体   繁体   中英

Why does this React component keep re rendering?

I have this Post component which mounts if the user types in the Id of an existing post in firebase:

<Route path='/posts/:id' component={Post} />

However, console logging this component sends back the log indefinitely causing my browser and actions on the page to be really slow.

Heres the content of the Post component, I think it's something to do with the way I'm setting the state in useEffect but I'm not sure how to fix it. I've tried React.Memo and that didn't work:

function Post(props: RouteComponentProps<PostParams>) {

  const [postData, setPostData] = useState({ title: '', body: '', author: '', time: 0, photoURL: '', likes: 0, dislikes: 0});
  const [existingComments, setExistingComments] = useState([])
  const [commentContent, setCommentContent] = useState('');
  const isMounted = useRef(false);
  const db = fb.firestore();
  const ref = db.doc(`posts/${props.match.params.id}`)

  useEffect(():any => {
    isMounted.current = true;
    ref.get().then((doc: any) => {
      if(doc.exists && isMounted.current) {
        setPostData(doc.data().content);
        setExistingComments(doc.data().comments ? doc.data().comments : [])
      }
    });
    return ()=> isMounted.current = false;
  });

  return ( 
  //... some html that displays the information I've got from firebase

Thanks in advance for your help:)

When you're updating the state inside useEffect , this triggers a rerender because of the state change and once the component updates, useEffect runs again which changes the state triggering another render cycle, because of this pattern your component keeps rerendering.

You can add a dependency array to tell useEffect to run only when the component mounts and also when something changes, like this:

function Post(props: RouteComponentProps<PostParams>) {

    const [postData, setPostData] = useState({ title: '', body: '', author: '', time: 0, photoURL: '', likes: 0, dislikes: 0 });
    const [existingComments, setExistingComments] = useState([])
    const [commentContent, setCommentContent] = useState('');

    useEffect((): any => {
        const db = fb.firestore();
        const ref = db.doc(`posts/${props.match.params.id}`)
        ref.get().then((doc: any) => {
            if (doc.exists && isMounted.current) {
                setPostData(doc.data().content);
                setExistingComments(doc.data().comments ? doc.data().comments : [])
            }
        });
        return () => { };
    }, [setPostData, setExistingComments]);
    // setPostData, setExistingComments won't get a new reference for every render so they won't cause useEffect to run
    return (<></>);
}

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