问题:
我有一个立法者集合放入一个表格,字段标题是按钮,并附加了点击事件,通过单击字段按钮对集合进行排序。
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的更新状态,表仍保持不变。
我认为我的问题是,议员的立法者组成部分没有更新其州。所以我的问题是你如何更新子组件的状态?
立法者的其他职能:
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>
);
}
}
答案 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;
});
}