渲染后如何根据另一个状态使用 setState 更新状态?
Posted
技术标签:
【中文标题】渲染后如何根据另一个状态使用 setState 更新状态?【英文标题】:How to update state using setState based on another state after rendering? 【发布时间】:2020-07-03 17:04:37 【问题描述】:我正在尝试在渲染 jsx 后根据其他状态更新状态。
有些状态已更新,但有些未更新。 请考虑检查“ComponentDidMount()”。我不确定发生了什么!为什么他们没有得到相应的更新? 我很困惑!
import React, Component from "react";
export class MathQuiz extends Component
constructor(props)
super(props);
this.state =
num1: 0,
num2: 0,
op_type: "",
op: "",
result: 0,
no_right: 0,
no_wrong: 0,
options: <li />,
ans_pos: 0,
options_and_pos: [[], 0]
;
componentDidMount()
this.genNums();
this.initQuiz(this.props.location.state.op_type);
initQuiz(op_type)
this.setState( op_type: op_type );
if (op_type === "Addition")
this.setState( op: "+" );
this.setState(prevState => ( result: prevState.num1 + prevState.num2 ));
/* Code */
else if (op_type === "Multiplication")
this.setState( op: "x" );
this.setState(prevState => ( result: prevState.num1 * prevState.num2 ));
console.log(this.state.result);
this.setState( options_and_pos: this.getOptions(this.state.result) );
this.setState(
options: this.state.options_and_pos[0].map((ele, i) => (
<li key=i>ele</li>
))
);
this.setState( ans_pos: this.state.options_and_pos[1] );
genNums()
this.setState(
num1: this.genRandRange(1, 100),
num2: this.genRandRange(1, 100)
);
getOptions(ans)
/* Code */
return [ans_options, rand_pos];
render()
return (
<div className="math_quiz_box">
/* JSX Code */
</div>
);
【问题讨论】:
状态被其他状态改变更糟糕。状态最好通过道具或事件处理程序来改变。 【参考方案1】:React docs 帮你:
setState() 并不总是立即更新组件。有可能 批处理或推迟更新。这使得阅读 this.state 就在调用 setState() 之后,这是一个潜在的陷阱。
并且还给你解决方案:
改为使用 componentDidUpdate 或 setState 回调 (setState(updater, callback)),其中任何一个都保证会触发 应用更新后。
因此,请确保在更新状态后不要立即使用状态。
【讨论】:
【参考方案2】:状态被其他状态改变更糟糕。由道具或事件处理程序更改状态会更好。
例如,this.genNums()
不必在componentDidMount()
中执行
this.setState(prevState => ( result: prevState.num1 + prevState.num2 ));
上面的代码可以修改为:
this.setState(result: 2*this.genRandRange(1, 100)) //assume this.genRandRange() return Number not String
整个段落都可以修改:
import React, Component from "react";
export class MathQuiz extends Component
constructor(props)
super(props);
this.state =
//num1: 0, if only used by other state
//num2: 0,
//op_type: "", if only used by other state
op: "",
result: 0,
no_right: 0,
no_wrong: 0,
options: <li />,
ans_pos: 0,
//options_and_pos: [[], 0] if only used by other state
;
componentDidMount()
this.initQuiz(this.props.location.state.op_type);
initQuiz(op_type)
if (op_type === "Addition")
this.setState(
op:"+",
result: 2*this.genRandRange(1, 100)
);
/* Code */
else if (op_type === "Multiplication")
this.setState(
op:"x",
result: Math.pow(this.genRandRange(1, 100),2),
options: this.getOptions(Math.pow(this.genRandRange(1, 100),2))[0].map((ele,
i) => (<li key=i>ele</li>)),
ans_pos:this.getOptions(Math.pow(this.genRandRange(1, 100),2))[1]
);
genNums()
this.setState(
num1: this.genRandRange(1, 100),
num2: this.genRandRange(1, 100)
);
getOptions(ans)
/* Code */
return [ans_options, rand_pos];
render()
return (
<div className="math_quiz_box">
/* JSX Code */
</div>
);
上面的代码,只做一次setState,可以防止无限循环或状态更新链等问题。
如果你必须做 setState 链,使用
this.setState(
example:"example value"
,()=>
// when example value has been set, then execute follow statement.
this.setState(
example2:this.state.example+"2" //example2:"example value2"
)
)
【讨论】:
以上是关于渲染后如何根据另一个状态使用 setState 更新状态?的主要内容,如果未能解决你的问题,请参考以下文章
React Native this.setState() 仅在再次与组件交互后重新渲染