ReactJS:警告:setState(...):在现有状态转换期间无法更新

时间:2016-05-23 09:29:38

标签: reactjs constructor setstate

我正在尝试从渲染视图中重构以下代码:

<Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChange.bind(this,false)} >Retour</Button>

到绑定在构造函数中的版本。原因是渲染视图中的绑定会给我带来性能问题,特别是在低端手机上。

我创建了以下代码,但我经常遇到以下错误(很多错误)。看起来应用程序进入循环:

Warning: setState(...): 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`.

以下是我使用的代码:

var React = require('react');
var ButtonGroup = require('react-bootstrap/lib/ButtonGroup');
var Button = require('react-bootstrap/lib/Button');
var Form = require('react-bootstrap/lib/Form');
var FormGroup = require('react-bootstrap/lib/FormGroup');
var Well = require('react-bootstrap/lib/Well');

export default class Search extends React.Component {

    constructor() {
        super();

        this.state = {
            singleJourney: false
        };

        this.handleButtonChange = this.handleButtonChange.bind(this);
    }

    handleButtonChange(value) {
        this.setState({
            singleJourney: value
        });
    }

    render() {

        return (
            <Form>

                <Well style={wellStyle}>

                    <FormGroup className="text-center">

                        <ButtonGroup>
                            <Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChange(false)} >Retour</Button>
                            <Button href="#" active={this.state.singleJourney} onClick={this.handleButtonChange(true)} >Single Journey</Button>
                        </ButtonGroup>
                    </FormGroup>

                </Well>

            </Form>
        );
    }
}

module.exports = Search;

11 个答案:

答案 0 :(得分:265)

看起来您在渲染方法中不小心调用了handleButtonChange方法,您可能希望改为onClick={() => this.handleButtonChange(false)}

如果您不想在onClick处理程序中创建lambda,我认为您需要有两个绑定方法,每个参数对应一个。

constructor

this.handleButtonChangeRetour = this.handleButtonChange.bind(this, true);
this.handleButtonChangeSingle = this.handleButtonChange.bind(this, false);

render方法中:

<Button href="#" active={!this.state.singleJourney} onClick={this.handleButtonChangeSingle} >Retour</Button>
<Button href="#" active={this.state.singleJourney} onClick={this.handleButtonChangeRetour}>Single Journey</Button>

答案 1 :(得分:4)

为了更好的理解,我给出了一个通用示例,在下面的代码中

render(){
    return(
      <div>

        <h3>Simple Counter</h3>
        <Counter
          value={this.props.counter}
          onIncrement={this.props.increment()} <------ calling the function
          onDecrement={this.props.decrement()} <-----------
          onIncrementAsync={this.props.incrementAsync()} />
      </div>
    )
  }

在提供道具时,我直接调用该函数,该循环执行无限循环,并且会给您该错误,请删除该函数,一切正常。

render(){
    return(
      <div>

        <h3>Simple Counter</h3>
        <Counter
          value={this.props.counter}
          onIncrement={this.props.increment} <------ function call removed
          onDecrement={this.props.decrement} <-----------
          onIncrementAsync={this.props.incrementAsync} />
      </div>
    )
  }

答案 2 :(得分:3)

如果您尝试向recompose中的处理程序添加参数,请确保在处理程序中正确定义参数。它本质上是一个curried函数,因此您需要确保需要正确数量的参数。 This page has a good example of using arguments with handlers.

示例(来自链接):

withHandlers({
  handleClick: props => (value1, value2) => event => {
    console.log(event)
    alert(value1 + ' was clicked!')
    props.doSomething(value2)
  },
})

为您的孩子HOC和父母

class MyComponent extends Component {
  static propTypes = {
    handleClick: PropTypes.func, 
  }
  render () {
    const {handleClick} = this.props
    return (
      <div onClick={handleClick(value1, value2)} />
    )
  }
}

这可以避免从处理程序中编写匿名函数来修补问题而不在处理程序上提供足够的参数名称。

答案 3 :(得分:2)

来自反应文档Passing arguments to event handlers

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

答案 4 :(得分:2)

render()调用中进行的任何状态更改都将发出相同的警告。

一个棘手的例子: 在基于状态数据呈现多选GUI组件时,如果state没有要显示的内容,则对resetOptions()的调用将被视为该组件的状态更改。

明显的解决方法是在resetOptions()中执行componentDidUpdate(),而不是render()

答案 5 :(得分:2)

通常在您致电时发生

onClick={this.handleButton () } -请注意(),而不是:

onClick={this.handleButton} -请注意,我们在初始化函数时并未调用该函数

答案 6 :(得分:2)

问题在这里:onClick={this.handleButtonChange(false)}

当您将this.handleButtonChange(false)传递给onClick时,实际上是在使用value = false调用该函数并将onClick设置为该函数的返回值(未定义)。另外,调用this.handleButtonChange(false)然后调用this.setState()会触发重新渲染,从而导致无限的渲染循环。

解决方案将以lambda形式传递函数:onClick={() => this.handleButtonChange(false)}。在这里,您将onClick设置为等于单击按钮时将调用handleButtonChange(false)的函数。

以下示例可能会有所帮助:

function handleButtonChange(value){
  console.log("State updated!")
}

console.log(handleButtonChange(false))
//output: State updated!
//output: undefined

console.log(() => handleButtonChange(false))
//output: ()=>{handleButtonChange(false);}

答案 7 :(得分:1)

我打电话时遇到同样的错误

Tooltip
handleClick不存在

时,在我的构造函数中

(我已经删除了它,并且在我的构造函数中意外地离开了#34;这个&#34;绑定语句。)

解决方案=删除&#34;此&#34;约束声明。

答案 8 :(得分:0)

我用来为组件打开Popover的解决方案是reactstrap (React Bootstrap 4 components)

spark-on-k8s

答案 9 :(得分:0)

问题肯定是在使用onClick处理程序出租按钮时的此绑定。解决方案是在渲染时调用动作处理程序时使用箭头功能。像这样:     onClick={ () => this.handleButtonChange(false) }

答案 10 :(得分:-1)

您不能在render方法上修改组件的状态,它会重新渲染,并且会陷入无限循环。该解决方案为我工作:http://txbmcode.com/index.php/2020/06/21/reactjs-error-cannot-update-during-an-existing-state-transition-such-as-within-render-render-methods-should-be-a-pure-function-of-props-and-state/