首页 > 解决方案 > 如何在 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() ?

标签: javascriptreactjs

解决方案


永远不要在渲染中执行 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 版本。


推荐阅读