Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Redux infinite loop

Tags:

reactjs

redux

I have the intention to perform a fetch to my rest api when ever the user updates an input bar. The problem I am having is that the componentDidUpdate method calls the action creator which dispatches the json to the reducer, in turn updating the state and calling componentDidUpdate again. Any ideas or best practices to end the endless cycle? Thanks!

Action Creator:

export const fetchFoods = (dispatch, searchText) => {
  return fetch(`/nutrition/${searchText}`)
    .then(res => res.json())
    .then(json => dispatch({type: 'RECEIVE_FOODS', json}))
}

Reducer:

const foods = (state = [], action) => {
  switch (action.type) {
    case 'RECEIVE_FOODS':
      return action.json
    default:
      return state
  }
}

React Container:

const FoodList = React.createClass({
  componentDidUpdate: function() {
    fetchFoods(this.props.dispatch, this.props.searchText)
  },
  componentWillMount: function() {
    fetchFoods(this.props.dispatch, this.props.searchText)
  },
  render: function() {
    ...
  }
})

export default connect(
  (state) => {
    return {searchText: state.searchText, foods: state.foods}
  }
)(FoodList)
like image 999
daniel Avatar asked Jul 13 '16 18:07

daniel


2 Answers

You should remove the fetchFoods function from the componentDidUpdate. Calling the function on an update will result in an infinite loop like you describe.

Once the component has mounted the first time and retrieved the original set of data, you should only call the action when it's explicitly required. If the user changes it, another function changes it, etc.

like image 166
David Meents Avatar answered Nov 19 '22 18:11

David Meents


Attach an onChange() handler to your input (or whatever you want to trigger an update), so that whenever input changes, it calls a function that explicitly dispatches that action.

https://jsfiddle.net/julianljk/69z2wepo/49105/

Function:

handleChange: function (e) {
    var myInput = e.target.value;
    this.setState({
        value: myInput
    });
    fetchFoods(this.props.dispatch, myInput) //sends it to the store, 
},        

Render:

render: function (){
    return( 
        <div>
            <input type="text" value={this.state.value} onChange={this.handleChange}/>
        </div>
)}    

Putting action dispatches in lifecycle methods can generally cause this sort of behavior.

like image 1
julianljk Avatar answered Nov 19 '22 18:11

julianljk