xploreraj
xploreraj

Reputation: 4362

React setState not re-rendering

In below code, state of Test is updating but its not re-rendering. I have updated the state of parent on button click on change of which I expected it to rerender the whole component including Button. But its not re-rendering Button. Need help wrt this. This is a test code and both classes are necessary.

import React from 'react';

class Button extends React.Component {
  constructor(props){
      super(props)
      this.state = {
          id : props.id
      }
  }
  render() {
      console.log('Button state id is', this.state.id)
      return(
          <div>
              'hi ' +  {this.state.id}
              <br/>
              <button type='submit' onClick={this.props.handleSubmit}>
                  submit
              </button>
          </div>
      )
  }
}

export default class App extends React.Component {
  constructor(props) {
      super(props)
      this.state = {
          id: 1
      }
      this.changeId = this.changeId.bind(this)
  }
  changeId() {
      let id = this.state.id
      console.log('parent state id is', id)
      this.setState({
          id: ++id
      })
  }
  render() {
      return(
          <Button id={this.state.id} handleSubmit={this.changeId}/>
      )
  }
}

EDIT: I have modified the code to remove obvious errors like not passing in changeId function to Button

EDIT 2: Found the solution here: React Child Component Not Updating After Parent State Change componentWillReceiveProps

Upvotes: 1

Views: 24433

Answers (4)

Vishal Kumar Sahu
Vishal Kumar Sahu

Reputation: 1396

The example for componentWillReceiveProps worked in my case, when I wanted to update child component of React on setState of parent component:

      componentWillReceiveProps(props) {
        this.setState({
          currentID: props.currentID
        });
      }

Upvotes: 0

Yogesh Devgun
Yogesh Devgun

Reputation: 1557

For a number to re render in the child component you need to make following changes to your code:

In current scenario value of id in changeId function is event, so you can't do ++id. You have to update it to:

changeId() {
    this.setState({
        id: ++this.state.id
    })
}

and for child component to re render the props value, you have to listen if there is any change in props. For that use componentDidUpdate lifecycle of react. Like this:

componentDidUpdate(prevProps){
   if (this.props.id !== prevProps.id) {
    this.setState({id: this.props.id});
  }
}

The other way is don't store props.id in child state. Use it directly in render.

class Button extends React.Component {

  render() {
      return(
          <div>
              'hi ' +  {this.props.id}
              <br/>
              <button type='submit' onClick={this.props.handleSubmit}>
                  submit
              </button>
          </div>
      )
    }
}

class App extends React.Component {
  constructor(props) {
      super(props)
      this.state = {
          id: 1
      }
      this.changeId = this.changeId.bind(this)
  }
  changeId() {
      this.setState({
          id: ++this.state.id
      })
  }
  render() {
      return(
          <Button id={this.state.id} handleSubmit={this.changeId}/>
      )
    }
}

ReactDOM.render(<App />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root" />

Upvotes: 3

Abhisar Tripathi
Abhisar Tripathi

Reputation: 1659

We can further optimise the component by doing something like this -: Highlights -:

  • changeId() { changed to changeId = () => { (fat arrow notation), if we use this we don't need this.changeId = this.changeId.bind(this);
  • Don't really need another component specially for button, can combine it in same component.
import React, {Component} from 'react'; 
export default class Test extends React.Component {
        constructor(props) {
            super(props)
            this.state = {
                id: 1
            }
        }
        changeId = () => {
            this.setState({
                id: ++this.state.id
            })
        }
        render() {
            return(
               <div>
                    'hi ' +  {this.state.id}
                    <br/>
                    <button type='submit' onClick={this.changeId}>
                        submit
                    </button>
                </div>
            )
        } }

Upvotes: 0

adam_th
adam_th

Reputation: 407

You haven't actually passed handleSubmit as a prop to the Button component. Assuming you want changeId() to be called when you click the button, try this:

class Test extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            id: 1
        }
        this.changeId = this.changeId.bind(this)
    }
    changeId() {
        console.log('change id called', id)
        this.setState({
            id: ++id
        })
    }
    render() {
        return(
            <Button id={id} handleSubmit={this.changeId}/>
        )
    }
}

Upvotes: 0

Related Questions