首页 文章

React:子组件不会在父级状态更改时呈现

提问于
浏览
0

在下面的示例中,Apps(父)组件及其子组件在启动时加载良好 . 但是,如果我选择使用新选项卡值更新状态的选项卡(调用handleClick),而不是使用更新的值重新呈现子组件(选项卡,内容),并且子道具未使用父状态更新 . 请指教 . PS:我添加了多个控制台日志以进行调试 .

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')
);

1 回答

  • 1

    您忘记了 bind 在App组件中的 handleClick 事件,使用此:

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

    您使用的方式应抛出错误,检查控制台:

    无法读取未定义的属性setState

    Suggestion:

    1. 在子组件事件中 props props 函数不是一个好主意,请使用 arrow function 来调用它们 .

    所以代替:

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

    用这个:

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

    2. 你正在使用 es6 ,所以你可以避免 .bind(this)map 体内维持正确的 context ,使用 arrow function ,如下所示:

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

    检查工作示例:

    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'/>
    

相关问题