最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React component only changes state on second onClick event - Stack Overflow

programmeradmin3浏览0评论

I have these two simplified React ponents, where the Times ponent is a child of the Create ponent (see below for code samples). The expected behavior is that initially, the Times ponent is not shown, but when the user clicks on the link with onClick, the Times ponent appears.

The ponents work as expected for the most part, but strangely, after clicking on the onClick link for the first time, the Times ponent does not appear and the Create ponent does not change state at all as is shown in the console. However, when clicking on the link a second time, the Create ponent does change state and rerenders, and the Times ponent is seen.

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'};
  },

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

  ponentWillReceiveProps: 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>
    );
  }
});

Output of console.log

false
true

Why is the state of the Create ponent not being registered on the first click?

I have these two simplified React ponents, where the Times ponent is a child of the Create ponent (see below for code samples). The expected behavior is that initially, the Times ponent is not shown, but when the user clicks on the link with onClick, the Times ponent appears.

The ponents work as expected for the most part, but strangely, after clicking on the onClick link for the first time, the Times ponent does not appear and the Create ponent does not change state at all as is shown in the console. However, when clicking on the link a second time, the Create ponent does change state and rerenders, and the Times ponent is seen.

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'};
  },

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

  ponentWillReceiveProps: 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>
    );
  }
});

Output of console.log

false
true

Why is the state of the Create ponent not being registered on the first click?

Share Improve this question asked Nov 24, 2015 at 3:34 LanceLafontaineLanceLafontaine 6,0104 gold badges22 silver badges34 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 17

The problem is here.

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

Which should be,

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

ComponentWillRecieveProps is a member function of the ponent class that gets called just before props are "applied". Which means that this.props are old Props. You should use newProps which is served to the function as an argument.

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


Also, I get the feeling that you are using a little more state than you need. You dont need the display as a state variable at all. Times is an inner ponent, so it makes sense to use props as much as possible and make them stateless.

There is a mon misconception around that "props change don't affect the render, so lets use state". Props change results in rerender too, so always use props unless there is a strong reason and you really need to make an inner ponent intelligent. Using props in inner ponents, makes them dumb and easier to use.

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>
    );
  }
});
发布评论

评论列表(0)

  1. 暂无评论