【发布时间】:2024-01-19 21:00:01
【问题描述】:
我有一个反应组件,它具有属性和状态。 state 的某些字段包含输入数据(从输入控件提升),但 state 中也有字段必须根据当前 State 和 Props 计算:
问题:更新状态计算字段的最佳方法是什么(基于状态和道具的其他字段)?
丑陋的做法:
componentDidUpdate(){
this.setState({calculatedField:calculate(this.props,this.state)}))
}
在这种情况下,我会获得无限循环的更新,或者在最好的情况下(如果我使用 PureComponent)双重渲染调用。
迄今为止我找到的最佳解决方案(但仍然很丑):
就是在 state 中创建一个calculated 对象,其中包含计算字段并在 componentWillUpdate 中更新,避免 setState:
componentWillUpdate(nextProps,nextState){
nextState.calculated.field1=f(nextProps,nextState)
}
class ParentComponent extends React.Component {
constructor(props, ctx) {
super(props,ctx)
this.state={A:"2"}
}
render() {
console.log("rendering ParentComponent")
return <div>
<label>A=<input value={this.state.A} onChange={e=>{this.setState({A:e.target.value})}} /></label> (stored in state of Parent component)
<ChildComponent A={this.state.A} />
</div>
}
}
class ChildComponent extends React.PureComponent {
constructor(props,ctx) {
super(props,ctx);
this.state={
B:"3",
Calculated:{}
}
}
render() {
console.log("rendering ChildComponent")
return <div>
<label>B=<input value={this.state.B} onChange={e=>{this.setState({B:e.target.value})}} /></label> (stored in state of Child component state)
<div>
f(A,B)=<b>{this.state.Calculated.result||""}</b>(stored in state of Child component)
<button onClick={e=>{ this.setState({Calculated:{result:new Date().toTimeString()}}) }}>Set manual value</button>
</div>
</div>
}
componentWillUpdate(nextProps, nextState) {
this.state.Calculated.result = getCalculatedResult(nextProps.A, nextState.B)
}
componentWillReceiveProps(nextProps) {
this.state.Calculated.result = getCalculatedResult(nextProps.A, this.state.B)
}
componentWillMount() {
this.state.Calculated.result = getCalculatedResult(this.props.A, this.state.B)
}
}
function getCalculatedResult(a,b) {
const aNum = Number(a)||0
const bNum = Number(b)||0;
const result = (aNum*bNum).toString();
return result;
}
ReactDOM.render(<ParentComponent/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.2.0/umd/react-dom.development.js"></script>
<div id="root"></div>
这也是一个丑陋的解决方案,React 不建议改变状态以避免 setState。那么什么是正确的解决方案呢?
注意:
在我的实际应用程序中,我无法在渲染过程中每次都重新计算 f(a,b),因为它实际上是一个复杂的对象,所以我需要以某种方式缓存它,最好的方法是在状态中。
【问题讨论】:
-
我认为你不应该在渲染中使用
setState,绑定一个方法并在那里设置状态。 -
@PaulRedmond,不确定你的意思。我不在渲染中调用 setState。你能提供一些代码示例吗?
-
您可以将计算结果保存在
this.calculated而不是this.state。它是依赖数据。所有导致更新和渲染的数据都已经在 state 和 props 中。 -
@PhilippMunin 你最后做了什么?
标签: javascript reactjs state