TRomesh
TRomesh

Reputation: 4481

React child component Re-renders without state change

Im passing some data from one component to another (parent to child). The data is passed without any issue from the enter and button click event. I have added some validations by considering some key events (whether numbers are entered). When ever the particular function related to this validation is triggered the child component auto manically re-renders. I cannot figure out why. here is my code. I have used flux architecture.

the main Parent(where keyevent takes place)

    const validatebox = (textStatus) => {

    if (textStatus.length > 100) {
      return {
              error: '*status is too long',
            };
    }  else if (textStatus === '') {
      return {
              error: '*status cannot be empty',
            };
    }  else {
      return true;
    }
}


class PaserBox extends React.Component{

      constructor(props) {
            super(props);
            this.state = {
              textStatus: '',
              tags:{},
              showResults: false
            };

      }

      parse = () => {

        let status = this.refs.textinput.getValue();

        if(validatebox(status).error) {
          this.setState({
            textStatus: validatebox(status).error
          });
          return;

        }
        else {

          Actions.SendDataToTag(status);
          this.setState({ showResults: true });
          console.log(status);


        }
          this.clearText();
      };

      clearText = () => {
        document.getElementById('language').value = '';
      };

      handleKey = (e) =>{
        if (e.key === 'Enter') {
            this.parse();
        } 
        else {
          var keycode = e.which;
          if ((e.shiftKey == false && (keycode == 46 || keycode == 8 || keycode == 37 || keycode == 39 || (keycode >= 48 && keycode <= 57)))) {
            this.setState({
                textStatus: 'cannot enter numbers'
            });
          }
          else {
            this.setState({
              textStatus: ''
            });
          }
        }
      };

      handleKeyDown = (e) => {
        if (e.keyCode == 8) {
          this.setState({
              textStatus: ''
          });
        }
      };

      render(){
        return(
          <div>
            <Paper className="row col-xs-12 col-sm-12 col-md-12" style={style} zDepth={1}>
              <div className="col-xs-12 col-sm-12 col-md-12 col-lg-12">
                <TextField
                  fullWidth={true}
                  style={textfieldstyle}
                  errorText={this.state.textStatus}
                  ref="textinput"
                  onKeyPress={this.handleKey}
                  onKeyDown={this.handleKeyDown}
                  hintText="Enter sentence ..."
                  className="col-xs-12 col-sm-12 col-md-12"
                  name="ta"
                  id="language"/>
              </div>
            <div className="col-xs-9 col-sm-9 col-md-9"/>
            <div className="col-xs-3 col-sm-3 col-md-3" style={style_button}>
              <RaisedButton  secondary={true} label="Parse" onTouchTap={this.parse}/>
            </div>
            <div className="col-xs-1 col-sm-1 col-md-1"/>
            </Paper>
            <label style={styles}>Please enter sentences with correct grammar</label>
            <br/>
            { this.state.showResults ?  <div className="row">
                                          <div className="col-md-10">
                                            <ParserTreeBox/>
                                          </div>
                                          <div className="col-md-2">
                                            <ParserTags/>
                                          </div>
                                        </div> : null }
          </div>
        );
      }

}

export default PaserBox;

the child component where the states change happens

   class ParserTreeBox extends React.Component{

  constructor(props) {
    super(props);
      this.state = {
        data: [],
        taggedData:{}
      }

     this._onChange = this._onChange.bind (this);
  }

  componentWillMount(){
    Store.addChangeListener(this._onChange);
  }

  componentWillUnmount(){
    Store.removeChangeListener(this._onChange);
  }

  _onChange(){
     this.setState({taggedData:Store.getData()});
  }

   render(){
     return(
        <div>
          <div>
            <ParserTree data={this.state.taggedData} />
          </div>
        </div>
     );
   }

}

export default ParserTreeBox;

Here the render function get triggered even though the states are not changed by the child components.I debugged the flux files they are working properly. Any reason why im getting this issue

Upvotes: 0

Views: 158

Answers (2)

Solo
Solo

Reputation: 6957

Change Component to PureComponent:

class MyComponent extends React.Component {

    // ...


class MyComponent extends React.PureComponent {

    // ...

It implements shouldComponentUpdate() with both a shallow prop and state comparison.

Upvotes: 1

Burak Karasoy
Burak Karasoy

Reputation: 1690

`Here the render function get triggered even though the states are
not changed by the child components

As far as I understand you have a setState function which triggers re render PaserBox and you don't want it to cause re render of ParserTreeBox which is child of PaserBox

If so it is quite normal that ParserTreeBox re renders because render function of PaserBox includes ParserTreeBox component.

When it is in render function of PaserBox it just passes data. But you can still neglect ParserTreeBox component re rendering shouldComponentUpdate(nextProps, nextState)function on ParserTreeBox side.

shouldComponentUpdate(nextProps, nextState){
 return this.state.taggedData == nextState.taggedData ? false : true
}

now it will check this method after that rendering of this component will be decided.

Upvotes: 1

Related Questions