【问题标题】:React: Child component not rendering on parents state change反应:子组件未在父状态更改时呈现
【发布时间】:2017-09-18 22:52:10
【问题描述】:

在下面的示例中,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')
);

【问题讨论】:

    标签: reactjs render


    【解决方案1】:

    你忘记bind App 组件中的handleClick 事件,使用这个:

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

    你使用的方式应该会报错,检查控制台:

    无法读取未定义的属性 setState

    建议:

    1.在子组件事件中bindprops函数不是个好主意,使用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'/>

    【讨论】:

    • 另外this.props.changeTab.bind(this, tab) 看起来很可疑,因为它在this 上调用了一个向下传递的函数。应该是() =&gt; this.props.changeTab(tab)。这就是它不会抛出错误的原因。
    • @Sulthan nice,在回答中提到了这一点:)
    猜你喜欢
    • 1970-01-01
    • 2017-05-05
    • 2019-09-17
    • 1970-01-01
    • 1970-01-01
    • 2021-07-07
    • 2019-06-26
    • 2023-03-18
    • 1970-01-01
    相关资源
    最近更新 更多