javascript - 如何在 React 的渲染函数中不使用 setState
问题描述
我有一个完整的运行代码,但它有一个缺陷。它从 render() 内部调用 setState()。所以,react 会抛出反模式警告。
Cannot update during an existing state transition (such as within render or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to componentWillMount
我的逻辑是这样的。在index.js父组件中,我有如下代码。constructor() 调用带有初始值的 graphs() 来显示一个图形。用户还有一个表单来指定新值并提交表单。它使用新值再次运行 graphs() 并重新渲染图形。
import React, { Component } from 'react';
import FormComponent from './FormComponent';
import PieGraph from './PieGraph';
const initialval = '8998998998';
class Dist extends Component {
constructor() {
this.state = {
checkData: true,
theData: ''
};
this.graphs(initialval);
}
componentWillReceiveProps(nextProps) {
if (this.props.cost !== nextProps.cost) {
this.setState({
checkData: true
});
}
}
graphs(val) {
//Calls a redux action creator and goes through the redux process
this.props.init(val);
}
render() {
if (this.props.cost.length && this.state.checkData) {
const tmp = this.props.cost;
//some calculations
....
....
this.setState({
theData: tmp,
checkData: false
});
}
return (
<div>
<FormComponent onGpChange={recData => this.graphs(recData)} />
<PieGraph theData={this.state.theData} />
</div>
);
}
}
FormComponent 是一个普通的表单,带有输入字段和一个提交按钮,如下所示。它将回调函数发送到父组件,该组件触发 graphs() 和 componentWillReceiveProps。
handleFormSubmit = (e) => {
this.props.onGpChange(this.state.value);
e.preventdefaults();
}
代码一切正常。有更好的方法吗?不做 setState 在 render() ?
解决方案
永远不要在渲染中执行 setState。您不应该这样做的原因是,对于每个 setState,您的组件都会重新渲染,因此在渲染中执行 setState 会导致无限循环,不推荐这样做。
不需要 checkData 布尔变量。您可以在 componentWillReceiveProps 中直接比较之前的成本和当前的成本,如果它们不相等,则使用 setState 将成本分配给 theData。请参阅下面的更新解决方案。
还要开始在所有有状态的组件中使用 shouldComponentUpdate 方法,以避免不必要的重新渲染。这是每个有状态组件中的一种最佳实践和推荐方法。
import React, { Component } from 'react';
import FormComponent from './FormComponent';
import PieGraph from './PieGraph';
const initialval = '8998998998';
class Dist extends Component {
constructor() {
this.state = {
theData: ''
};
this.graphs(initialval);
}
componentWillReceiveProps(nextProps) {
if (this.props.cost != nextProps.cost) {
this.setState({
theData: this.props.cost
});
}
}
shouldComponentUpdate(nextProps, nextState){
if(nextProps.cost !== this.props.cost){
return true;
}
return false;
}
graphs(val) {
//Calls a redux action creator and goes through the redux process
this.props.init(val);
}
render() {
return (
<div>
<FormComponent onGpChange={recData => this.graphs(recData)} />
{this.state.theData !== "" && <PieGraph theData={this.state.theData} />}
</div>
);
}
}
PS:- 以上解决方案适用于 React v15 版本。
推荐阅读
- laravel - Laravel 和 Markdown 电子邮件 - 隐藏特定邮件的页脚
- hangouts-chat - 如何在 Google 聊天中为我的团队创建群组名称?
- pip - 在 YAML 文件中指定 conda 和 pip 包版本号时 = 和 == 等是什么意思
- excel - 函数输入数据类型是否影响循环速度/效率
- c# - 有什么方法可以将数据表行绑定到 UWP 中的 DataGrid
- python - 通过 ezgmail 发送的电子邮件正文部分分成几行。(Pycharm 中的 Python 3.8)
- docker - 将 CSV 文件加载到 MariaDB 中,通过 python 自动创建表
- php - 如何正确设置 jQuery ajax 以在 Wordpress 中上传文件?
- synthesis - 如何在 Yosys ABC 实施步骤中保留电线
- python - 如何在循环中打印字符串与字符串列表的连接