React 组件仅在第二个 onClick 事件上更改状态

React component only changes state on second onClick event

我有这两个 简化的 React 组件,其中 Times 组件是 Create 组件的子组件(代码示例见下文)。预期的行为是,最初未显示 Times 组件,但当用户单击带有 onClick 的 link 时,会出现 Times 组件。

这些组件大部分都按预期工作,但奇怪的是,在第一次单击 onClick link 后,Times 组件没有出现并且 Create 组件根本没有改变状态,如控制台所示。但是,当第二次单击 link 时,Create 组件确实会更改状态并重新呈现,并且会看到 Times 组件。

Create.jsx

import React from 'react';
import Times from './Times.jsx';

export default React.createClass({

  getInitialState: function () {
    return {times: false};
  },

  _change: function () {
    this.replaceState({times: true});
    console.log(this.state.times);
  },

  render: function () {
    return (
      <div id="create">
        <div id="outerbox">
          <a onClick={this._change}>Times</a>
          <Times shouldShow={this.state.times}/>
        </div>
      </div>
    );
  }
});

Times.jsx

import React from 'react';

export default React.createClass({

  propTypes: {
    shouldShow: React.PropTypes.bool.isRequired
  },

  getDefaultProps: function () {
    return {shouldShow: false};
  },

  getInitialState: function () {
    return {el: 'times'};
  },

  componentDidMount: function() {
    if (this.props.shouldShow === false) {
      this.setState({display: 'none'});
    } else {
      this.setState({display: 'block'});
    }
  },

  componentWillReceiveProps: function() {
    if (this.props.shouldShow === false) {
      this.setState({display: 'none'});
    } else {
      this.setState({display: 'block'});
    }
  },

  render: function () {
    return (
      <div id={this.state.el} style={{"display": this.state.display}}>
        <h1>Times</h1>
      </div>
    );
  }
});

console.log

的输出
false
true

为什么 Create 组件的状态在第一次点击时没有被注册?

问题就在这里

 componentWillReceiveProps: function() {
    if (this.props.shouldShow === false) {
      this.setState({display: 'none'});
    } else {
      this.setState({display: 'block'});
    }
  }

应该是,

 componentWillReceiveProps: function(newProps) {
    if (newProps.shouldShow === false) {
      this.setState({display: 'none'});
    } else {
      this.setState({display: 'block'});
    }
  }

ComponentWillRecieveProps 是组件 class 的成员函数,它在 props "applied" 之前被调用。这意味着 this.props 是旧的 Props。您应该使用作为参数提供给函数的 newProps

http://codepen.io/bhargav175/pen/gaJmKz


另外,我感觉你使用的状态比你需要的多了一点。您根本不需要将显示作为状态变量。 Times 是一个内部组件,因此尽可能使用 props 并使其无状态是有意义的。

围绕 "props change don't affect the render, so lets use state" 有一个普遍的误解。道具在重新渲染时也会改变结果,所以除非有充分的理由并且您确实需要使内部组件智能化,否则请始终使用道具。在内部组件中使用 props,使它们变笨并且更易于使用。

http://codepen.io/bhargav175/pen/WQBpzP

   var Times = React.createClass({

  propTypes: {
    shouldShow: React.PropTypes.bool.isRequired
  },

  getDefaultProps: function () {
    return {shouldShow: false};
  },

  getInitialState: function () {
    return {el: 'times'};
  },



  render: function () {
    let display = this.props.shouldShow ? "block" : "none";
    return (
      <div id={this.state.el} style={{"display": display}}>
        <h1>Times</h1>
      </div>
    );
  }
});