Search code examples
reactjsreact-reduxreact-hooksuse-effect

Redux dispatch in useEffect causing infinite rerender


I have tried searching previous similar questions but many of the answers suggest passing in a dependency array to useEffect, which I already have done.

This is basically a user's show page:

const Profile = ({ currentUser, profileOwner, getProfileInfo, isMine }) => {
  useEffect(() => {
    getProfileInfo();
  }, [profileOwner]);

  return (stuff)
}

This is its container:

const mapStateToProps = ({ session, users }, ownProps) => ({
  currentUser: users[session.id],
  profileOwner: users[ownProps.params.userId],
  isMine: session.id === parseInt(ownProps.params.userId),
});

const mapDispatchToProps = (dispatch, ownProps) => ({
  getProfileInfo: () => dispatch(getProfileInfo(ownProps.params.userId)),
});

And this is the action that I assume is somehow causing the re-render:

export const getProfileInfo = (userId) => (dispatch) =>
  axios.get(`/api/users/${userId}`).then((res) => res.data)
    .then((user) => dispatch(receiveProfileOwner(user)));

If I take profileOwner out of the dependency array, there is no more infinite loop, but then it won't fetch the user data if I navigate to a different user's profile. As far as I can see, the value of profileOwner shouldn't be changing at all after it was fetched the first time, so it is still a puzzle to me why I have this problem.


Solution

  • It looks like using profileOwner as the dependency was the mistake. The component already receives the routing params as props, so I changed the useEffect to this:

    const Profile = ({ currentUser, profileOwner, getProfileInfo, isMine, params: { userId } }) => {
      useEffect(() => {
        getProfileInfo();
      }, [userId]);
    

    It's kind of messy, and I expect that there is a better way to do this than adding more props, but it does solve the problem.