更改状态后React不重新呈现,如何设置子组件的状态?

时间:2017-02-01 01:28:06

标签: javascript reactjs

问题:

我有一个立法者集合放入一个表格,字段标题是按钮,并附加了点击事件,通过单击字段按钮对集合进行排序。

render() {
    const legislatorList = this.populateList() //  creates an Array of Legislator components
    return (
      <div className="legislators">
        <h2>Legislators</h2>
        <table className="table table-bordered">
        <thead>
          <tr>
            <th><button type="button" onClick={ () => this.handleChange("first_name")}  >First</button></th>
            <th><button type="button" onClick={ () => this.handleChange("last_name")}  >Last</button></th>
            <th><button type="button" onClick={ () => this.handleChange("state")}  >State</button></th>
            <th><button type="button" onClick={ () => this.handleChange("party")}  >Party</button></th>
          </tr>
        </thead>
          <tbody>
            { legislatorList }
          </tbody>
        </table>
      </div>
    );

click事件会将this.state.legislators重新分配给sort函数的输出。

handleChange( value ) {
    this.setState( { legislators: this.sort_by( value) })
  }

但即使已正确排序state.legislators的更新状态,表仍保持不变。

我认为我的问题是,议员的立法者组成部分没有更新其州。所以我的问题是你如何更新子组件的状态?

在任何排序之前: enter image description here

按名字排序后: enter image description here

立法者的其他职能:

sort_by(sort_by) {
  const sorted = this.state.legislators.sort(function(a, b) {
    a_val = a[sort_by]
    b_val = b[sort_by]
    if (a_val < b_val) {
      return -1;
    }
    if (a_val > b_val) {
      return 1;
    }
    return 0;
  });
  return sorted
}

renderLegislator(legislator) {
  return <Legislator legislator={ legislator}/>
}

populateList() {
  return this.state.legislators.map((legislator) =>
    this.renderLegislator(legislator)
  )}
}

以下是立法者组成部分:

class Legislator extends React.Component {
  constructor(props) {
    super();
    this.state = {
      legislator: props.legislator,
      fields: ["first_name", "last_name", "state", "party"]
    }
  }

  render() {
    const legislatorRow = this.state.fields.map((field) =>
        <LegislatorField value={ this.state.legislator[field] } />
    )
    return (
      <tr key={this.state.legislator.id}>
        { legislatorRow }      
      </tr>
    );
  }
}

2 个答案:

答案 0 :(得分:5)

您的子组件中的state.legislator未更新,因为代码:

this.state = {
  legislator: props.legislator,
  fields: ["first_name", "last_name", "state", "party"]
}

只运行一次,因为构造函数也只运行一次。除非您在子组件中明确执行state.legislator,否则子组件中的this.setState()将不会自动更新。

但是,没有必要以这样的方式做。在子组件中维护props的自身状态绝对是多余的。

您可以在子组件中的this.props方法中直接使用render,当父组件中的state更改时,子项将使用新的道具重新呈现。

 class Legislator extends React.Component {
  constructor(props) {
    super();
    this.state = {
      fields: ["first_name", "last_name", "state", "party"]
    }
  }

  render() {
    const legislatorRow = this.state.fields.map((field) =>
        <LegislatorField value={ this.props.legislator[field] } />
    )
    return (
      <tr key={this.state.legislator.id}>
        { legislatorRow }      
      </tr>
    );
  }
}

作为奖励,如果您的this.state.fields始终保持不变 - 您不打算稍后更新它,您也不必将其作为状态。您只需将其作为this.fields = ["first_name", "last_name", "state", "party"]

的类实例字段即可

答案 1 :(得分:3)

主要问题是Array.prototype.sort改变了数组并返回它,而不是返回一个新的数组。

 a = [4,1,2,3];
 b = a.sort();
 a === b // true , they are the same object

所以当你&#34;改变状态&#34;在handleChange中,您实际上正在改变指定相同对象引用的状态,因此很难让React告诉您已经进行了任何更改。

最简单的方法是使用Immutable来存储立法者的集合。使用Immutable.List.sort,你将得到一个带有新值的新数组,而不是旧数组的变异。

其他方法是通过在状态上具有sortBy属性来更清楚地定义组件,该属性包含对列表进行排序的键,并更新而不是整个集合。

<强> constructor

this.state = {
  legislator: props.legislator,
  fields: ["first_name", "last_name", "state", "party"],
  sortBy: 'first_name'
}

<强> handleChange

handleChange( value ) {
  this.setState( { sortBy: value })
}

<强> populateList

populateList() {
  return this.state.legislators.map((legislator) =>
    this.renderLegislator(legislator)
  ).sort(function(a, b) {
     a_val = a[this.state.sortBy]
     b_val = b[this.state.sortBy]
     if (a_val < b_val) {
       return -1;
     }
     if (a_val > b_val) {
       return 1;
     }
     return 0;
   });
}