【问题标题】:ReactJS why will this state change not render? What am I doing wrong?ReactJS 为什么这个状态改变不会渲染?我究竟做错了什么?
【发布时间】:2016-12-30 16:33:36
【问题描述】:
import React from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';

var mode=['recent', 'alltime'];

var Button = React.createClass({
  render(){
    return <input type={this.props.type} onClick=    {this.props.onClick} text={this.props.val}/>;
  }
});

class Header extends React.Component {
  constructor(){
    super()
  }

  render(){
    return <h2>Free Code Camp Leader board</h2>
  }
}

class Leader extends React.Component{
  constructor(props){
    super(props)
    this.state = {
      users: [],
      val: props.m,
    }
  }

  componentDidMount() {
    var th =this;
    this.serverRequest = axios.get("https://fcctop100.herokuapp.com/api/fccusers/top/"+this.state.val).then(function(result){
      console.log(result.data);
      var leaders = result.data;
      this.setState({
        users: leaders
      });
    }.bind(this));
  }

  componentWillUnmount() {
    this.serverRequest.abort();
  }

  render(){
    return (
      <div className='container'>

        <div className="tbl">
          <table className="table">
            <thead>
              <tr>
                <th>Name</th>
                <th>Recent </th>
                <th>Alltime</th>
              </tr>
            </thead>
            <tbody>
              {this.state.users.map(function(data, index){
                return (<tr key={index}><td><img src={data.img}    className="img img-thumbnail" width="50"/>{data.username}</td> 
                <td id='recent'>{data.recent}</td> 
                <td id='alltime'>{data.alltime}</td></tr>)
              })}
            </tbody>
          </table>
        </div>
      </div>
    )
  }
}


class App extends React.Component{
  constructor(){
    super(),
    this.state={val: mode[0]},
    this.update= this.update.bind(this),
    this.unmount=this.unmount.bind(this)
  }

  unmount(){
    ReactDOM.unmountComponentAtNode(document.getElementById('board'))
  }

  update(){
    this.unmount();
    this.setState({val: this.state.val ===mode[0]? mode[1] : mode[0]});
  }

  render(){
    return (
      <div>
        <div className='header'>
          <Header />
          <button  onClick={this.update}  >{this.state.val==mode[0]? mode[1] : mode[0]}</button>
        </div>
        <div id="board">
          {this.state.val === mode[0]? <Leader m= {this.state.val} /> : this.state.val ===
            mode[1] ? <Leader m= {this.state.val} /> : null}
        </div>
      </div>
    );
  }
}

export default App;

有问题的部分是在类 App extends React.Component 下。我正在尝试使用更新方法中的状态更改重新渲染领导者组件。它会更改状态,但不会更改传递给 Leader 以重新渲染的属性。

【问题讨论】:

  • 打电话unmount()的目的是什么。如果你只是评论那条线,你有同样的行为吗?
  • 我认为问题是componentDidMount 仅在初始渲染发生后立即在客户端(而不是服务器)上调用一次。如果您将 this.state.val 移动到领导者渲染,它应该会更新。
  • 好的,谢谢,是的,unmount() 函数只是一个尝试在 val 属性上的 steState 之前卸载 Leader 的实验。目前它是一个无用的功能,很可能需要删除。
  • 小提示:如果你将get调用中的匿名函数回调改为(result) =&gt; {},那么你就不需要在最后调用bind(this),因为=&gt;("箭头") 函数在词法上传递 this.

标签: javascript reactjs


【解决方案1】:

在初始渲染后,您没有在 Leader 内部使用道具 m 做任何事情。所以,它正在重新渲染,但它的状态没有改变。请记住,constructor 仅在初始 render 之前被调用一次。因此,如果您希望 Leader 在初始 render 之后响应 prop 更改并相应地更新其状态,则需要使用 component lifecycle methods 之一。

我建议将componentWillReceiveProps lifecycle method 添加到您的Leader 组件中。应该这样做:

componentWillReceiveProps(nextProps) {
  this.setState({ val: nextProps.m });
}

要测试组件内部发生的情况,任何简单的方法就是添加一个console.log(this.props, this.state); 作为组件render 的第一行。

【讨论】:

  • 好的,谢谢你,当我回到电脑前我会试试这个方法,让你知道它是如何工作的。我认为这实际上可以解决问题。
  • 我觉得这个方案不错,但是值得问一下,是否需要将App状态复制到Leader中?为什么不在领导者内部使用props.m
  • 同意。我只是想向 OP 展示他/她在当前实施中做错了什么。
  • 我使用App状态值作为传递给Leader的属性,因为App中呈现的按钮和关联的更新方法应该决定leader中的api调用方法,其中有两个选项我正在尝试在两者之间切换。您指的是解决该问题的更有效方法吗?
  • @ChadD @azium 建议(我同意),您不需要将val 保持在Leader 的状态。您可以将... + this.state.val 替换为... + this.props.m。这样你就不用担心在Leader 的父级传入新的m 属性时更新val 的状态。
猜你喜欢
  • 2013-08-06
  • 1970-01-01
  • 2016-07-18
  • 2023-03-25
  • 1970-01-01
  • 2011-04-30
  • 2021-03-05
  • 2016-05-27
  • 2019-12-23
相关资源
最近更新 更多