user5780883
user5780883

Reputation:

React - updating state during render produces errors

I'm new to React and am trying to update the state of a parent component from the child everytime an onChange action happens. The onchange action comes from an input box that when letters are typed it updates the state of searchInputVal with the value of what has been typed. I have a parent <App/> component with the following properties and states here:

updateSampleFilteredState(filteredSamples) {
    this.setState({
        samples: filteredSamples
    });  
},
getInitialState () {
    return {
        samples:allSamples,
        searchInputVal:""

}}

I pass the properties and states down to a child component here:

updateNewSampleState(filteredSamples){
    return (
        this.props.updateSampleFilteredState(filteredSamples)
        )
}
render() {
    const filteredSamples = this.props.samples.filter(sample => {
        return sample.sampleFamily.toLowerCase().indexOf(this.props.searchInputVal.toLowerCase()) !== -1;
    });
    this.updateNewSampleState(filteredSamples);
    return <div className="samples-container-inner-styling">
    {
    filteredSamples.map((sample) => {
    return (...

Before I added the line this.updateNewSampleState(filteredSamples); the child component would render out the filtering just fine but obviously not update the state of sample with the new filtered state. When I the line this.updateNewSampleState(filteredSamples); to execute the function in the component to set the new state I get a list of re-occuring errors that eventually make my app crash. The errors say something about an anti pattern. I'm not sure how else to update the state?

Upvotes: 3

Views: 780

Answers (2)

Felix Kling
Felix Kling

Reputation: 816452

As already mentioned by @César, setting the state in the renderer doesn't make sense, since setting the state triggers a rerender of the component, so you basically get something like an infinite render loop.

Given that you are computing filteredSamples only from the props, you could compute that state in the constructor:

The constructor is the right place to initialize state.

However, note the following when deriving state from props in the constructor:

It's okay to initialize state based on props if you know what you're doing. [...]

Beware of this pattern, as it effectively "forks" the props and can lead to bugs. Instead of syncing props to state, you often want to lift the state up.

If you "fork" props by using them for state, you might also want to implement componentWillReceiveProps(nextProps) to keep the state up-to-date with them. But lifting state up is often easier and less bug-prone.

Upvotes: 0

C&#233;sar Landesa
C&#233;sar Landesa

Reputation: 2656

You should't be updating the state from the render function, and you are facing the reason why that's a bad way to do things. Every time you call the setState the component re-renders, so if you call it inside the render function it will be called again and so on... You should ask yourself why are you calling that function there. I guess you could just do it in the onChange function you are using for the input.

Upvotes: 2

Related Questions