React: Child component not rendering on parents state change

Ashish

In the below example, Apps (parent) component and its child components loads well on the startup. But if I select the tab (call handleClick) which updating the state with new tab value not re-rendering the child components (tabs, content) with updated value and the child props are not updating with parent state. Please advise. PS: I have added multiple console log for debugging purpose.

import React, { Component } from 'react';
var tabData = [
  {name: 'Tab 1', isActive: true},
  {name: 'Tab 2', isActive: false},
  {name: 'Tab 3', isActive: false}
];
export class Tabs extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      activeTab: props.activeTab
    };
  }

  componentWillReceiveProps(nextProps) {
    console.log("Tabs:componentWillReceiveProps $$$$$$", this);
    this.setState({activeTab: nextProps.activeTab});
  }

  render() {
    console.log("Tabs $$$$$$", this.props);
    return (

      <ul className="nav nav-tabs">
        {
          tabData.map(function (tab, index) {
            // console.log("####", this.props.activeTab);
            return (
              <Tab key={index} data={tab} isActive={this.props.activeTab === tab}
                   handleClick={this.props.changeTab.bind(this,tab)}/>
            );
          }.bind(this))}
      </ul>
    )
      ;
  }
}
export class Tab extends React.Component {
  componentWillReceiveProps(nextProps) {
    console.log("Tab:componentWillReceiveProps $$$$$$", nextProps);

  }

  render() {
    console.log("Tab $$$$$$", this.props);
    return (
      <li onClick={this.props.handleClick} className={this.props.isActive ? "active" : null}>
        <a href="#">{this.props.data.name}</a>
      </li>
    );
  }
}
export class Content extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      activeTab: props.activeTab
    };
  }

  componentWillReceiveProps(nextProps) {
    console.log("Tabs:componentWillReceiveProps $$$$$$", nextProps);

  }

  render() {
    console.log("Content $$$$$$", this.state.activeTab);
    console.log("Content props $$$$$$", this.props.activeTab);
    return (
      <div>
        {this.state.activeTab.name === 'Tab 1' ?
          <section className="panel panel-success">
            <h2 className="panel-heading">Content 1</h2>

            <p className="panel-body">chart1</p>

            <p className="panel-body">handsontable1</p>
          </section>
          : null}
        {this.state.activeTab.name === 'Tab 2' ?
          <section className="panel panel-warning">
            <h2 className="panel-heading">Content 2</h2>

            <p className="panel-body">chart2</p>

            <p className="panel-body">handsontable2</p>
          </section>
          : null}
        {this.state.activeTab.name === 'Tab 3' ?
          <section className="panel panel-danger">
            <h2 className="panel-heading">Content 3</h2>

            <p className="panel-body">chart3</p>

            <p className="panel-body">handsontable3</p>
          </section>
          : null}
      </div>
    );
  }
}
export class App extends React.Component {
  constructor(props) {
    super(props);
    //this.activeTabs = tabData[0];
    this.state = {
      activeTab: tabData[0]
    }
  }


  handleClick(tab) {
    debugger;
    console.log("1handleClick*****", tab, this);
    this.setState({activeTab: tab});
    console.log("2handleClick*****", this);
  }

  render() {
    console.log("App $$$$$$", this.state.activeTab);
    return (
      <div>
        <Tabs activeTab={this.state.activeTab} changeTab={this.handleClick}/>
        <Content activeTab={this.state.activeTab}/>
      </div>
    );
  }
}

React.render(
  <App />,
  document.getElementById('app')
);
Mayank Shukla

You forgot to bind the handleClick event in App component, Use this:

changeTab={this.handleClick.bind(this)}

The way you are using should throw the error, check the console:

Can't read property setState of undefined

Suggestion:

1. It's not a good idea to bind the props functions in child component events, use arrow function to call them.

So instead of:

handleClick={this.props.changeTab.bind(this,tab)}

Use this:

handleClick={() => this.props.changeTab(tab)}

2. Your are using es6, so you can avoid the .bind(this) to maintain the proper context inside map body, use arrow function, like this:

tabData.map( (tab, index) => {
     return (
        <Tab key={index} data={tab} isActive={this.props.activeTab === tab} handleClick={this.props.changeTab.bind(this,tab)}/>
     );
})

Check the working example:

var tabData = [
  {name: 'Tab 1', isActive: true},
  {name: 'Tab 2', isActive: false},
  {name: 'Tab 3', isActive: false}
];

class Tabs extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      activeTab: props.activeTab
    };
  }

  componentWillReceiveProps(nextProps) {
    this.setState({activeTab: nextProps.activeTab});
  }

  render() {
    return (

      <ul className="nav nav-tabs">
        {
          tabData.map(function (tab, index) {
            return (
              <Tab key={index} data={tab} isActive={this.props.activeTab === tab}
                   handleClick={this.props.changeTab.bind(this,tab)}/>
            );
          }.bind(this))}
      </ul>
    )
      ;
  }
}

class Tab extends React.Component {
  componentWillReceiveProps(nextProps) {
  }

  render() {
    return (
      <li onClick={this.props.handleClick} className={this.props.isActive ? "active" : null}>
        <a href="#">{this.props.data.name}</a>
      </li>
    );
  }
}

class Content extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      activeTab: props.activeTab
    };
  }

  componentWillReceiveProps(nextProps) {
  }

  render() {
    return (
      <div>
        {this.state.activeTab.name === 'Tab 1' ?
          <section className="panel panel-success">
            <h2 className="panel-heading">Content 1</h2>

            <p className="panel-body">chart1</p>

            <p className="panel-body">handsontable1</p>
          </section>
          : null}
        {this.state.activeTab.name === 'Tab 2' ?
          <section className="panel panel-warning">
            <h2 className="panel-heading">Content 2</h2>

            <p className="panel-body">chart2</p>

            <p className="panel-body">handsontable2</p>
          </section>
          : null}
        {this.state.activeTab.name === 'Tab 3' ?
          <section className="panel panel-danger">
            <h2 className="panel-heading">Content 3</h2>

            <p className="panel-body">chart3</p>

            <p className="panel-body">handsontable3</p>
          </section>
          : null}
      </div>
    );
  }
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      activeTab: tabData[0]
    }
  }


  handleClick(tab) {
    this.setState({activeTab: tab});
    console.log("2handleClick*****", tab);
  }

  render() {
    return (
      <div>
        <Tabs activeTab={this.state.activeTab} changeTab={this.handleClick.bind(this)}/>
        <Content activeTab={this.state.activeTab}/>
      </div>
    );
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id='app'/>

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

React child component not re-rendering on state change

React: Click on a component to change parents state

React - Change state in child component

React state updating but not rendering on child component

React-Redux : Child component not re-rendering on parent state change when using connect() in child

why child components div in react is not re rendering even though child component re renders at state change

React native child component did not get componentWillReceiveProps from parents state

React Update Child's state from Parents Component

Parent React component not re-rendering on change state in child using react hooks;

React component not re-rendering on state change

Updating React child component after state change

React: avoid child component rerender on state change

Parent component unnecessarily re-rendering child on parent state change

How to stop child component re-rendering on parent state change?

React component not re-rendering on component state change

React Child Component not re-rendering mapped state

React child component not re-rendering on state update

React js change child component's state from parent component

React State change is not Rendering

React Child Component not re-rendering when props change

React-redux component is not re-rendering after state change

React component rendering even when there is no change in the state value

React functional component is not re-rendering on state change

React Js component rendering only once after state change

React native: rendering conditional component based on state value change in Modal

React functional component not re-rendering with state change

React component not re-rendering on state change using setState

my component is not re-rendering on state change react native

Component not re-rendering after change in an array state in react

TOP Ranking

HotTag

Archive