infinite loop when dispatching in componentWillReceiveProps

13,950

Solution 1

Your componentWillReceiveProps is in an infinite loop because calling fetchUser will dispatch an action that will update the Props.

Add a comparison to check if the specific prop changes before dispatching the action. EDIT:

In React 16.3+ componentWillReceiveProps will be slowly deprecated.

It is recommended to use componentDidUpdate in place of componentWillReceiveProps

componentDidUpdate(prevProps) {
  if (this.props.params.username !== prevProps.params.username) {
    dispatch(fetchUser(username));
  }
}

See https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#fetching-external-data-when-props-change

Solution 2

Try adding a condition to compare the props. If your component needs it.

componentWillRecieveProps(nextProps){
 if(nextProps.value !== this.props.value)
  dispatch(action()) //do dispatch here 
}

Solution 3

If you have react routes with some path params like profile/:username, You can simply compare the props.location.pathname

componentWillReceiveProps(nextProps){    
    if(nextProps.location.pathname !== this.props.location.pathname){
          dispatch()
        }
 }  
Share:
13,950
hazmah0
Author by

hazmah0

Updated on June 08, 2022

Comments

  • hazmah0
    hazmah0 almost 2 years

    I have a Profile component that is loaded by react-router (path="profile/:username") and the component itself looks like this:

    ...
    import { fetchUser } from '../actions/user';
    
    class Profile extends Component {
      constructor(props) {
        super(props);
      }
      componentDidMount() {
        const { username } = this.props;
        this.fetchUser(username);
      }
      componentWillReceiveProps(nextProps) {
        const { username } = nextProps.params;
        this.fetchUser(username);
      }
      fetchUser(username) {
        const { dispatch } = this.props;
        dispatch(fetchUser(username));
      }
      render() {...}
    }
    
    export default connect((state, ownProps) => {
      return {
        username: ownProps.params.username,
        isAuthenticated: state.auth.isAuthenticated
      };
    })(Profile);
    

    And the fetchUser action looks like this (redux-api-middleware):

    function fetchUser(id) {
      let token = localStorage.getItem('jwt');
      return {
        [CALL_API]: {
          endpoint: `http://localhost:3000/api/users/${id}`,
          method: 'GET',
          headers: { 'x-access-token': token },
          types: [FETCH_USER_REQUEST, FETCH_USER_SUCCESS, FETCH_USER_FAILURE]
        }
      }
    }
    

    The reason I added componentWillReceiveProps function is to react when the URL changes to another :username and to load that users profile info. At a first glance everything seems to work but then I noticed while debugging that componentWillReceiveProps function is called in a infinite loop and I don't know why. If I remove componentWillReceiveProps then the profile doesn't get updated with the new username but then I have no loops problem. Any ideas?

  • hazmah0
    hazmah0 about 8 years
    I understand now. The reducer for FETCH_USER_SUCCESS stored som user data which my Profile component was connecting over (which I forgot to add to my code above when writing the question). So the flow was componentWillReceiveProps --> dispatcher --> reducer updates data that Profile connects on --> componentWillReceiveProps is called again and it all starts over. I think I will need to move the code for route changes somewhere else to avoid this loop. Thanks!