【问题标题】:ES6 - Warning: setState(…): Cannot update during an existing state transitionES6 - 警告:setState(…):在现有状态转换期间无法更新
【发布时间】:2017-05-16 13:33:38
【问题描述】:

我正在重写一些旧的 ReactJS 代码,并且在修复这个错误时遇到了困难(错误在控制台中重复了大约 1700 次,DOM 根本不渲染):

警告:setState(...):在现有状态期间无法更新 过渡(例如在render 或其他组件的 构造函数)。渲染方法应该是 props 的纯函数和 状态;构造函数副作用是一种反模式,但可以移动 到componentWillMount

我是一个组件,它将它的状态传递给一个应该呈现一些控件的组件。根据单击的控件,状态应该会发生变化,并且应该呈现新的控件。

这是我的容器组件:

class TeaTimer extends Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 120,
            countdownStatus: 'started'
        }
    }

    componentDidUpdate(prevProps, prevState) {
        if (this.state.countdownStatus !== prevState.countdownStatus) {
            switch (this.state.countdownStatus) {
                case 'started':
                    this.startTimer();
                    break;
                case 'stopped':
                    this.setState({count:0});
            }
        }
    }

    componentWillUnmount() {
        clearInterval(this.timer);
        delete this.timer;
    }

    startTimer() {
        this.timer = setInterval(() => {
            let newCount = this.state.count -1;
            this.setState({
                count: newCount >= 0 ? newCount : 0
            });
            if(newCount === 0) {
                this.setState({countdownStatus: 'stopped'});
            }
        }, 1000)
    }

    handleStatusChange(newStatus) {
        this.setState({ countdownStatus: newStatus });
    }

    render() {
        let {count, countdownStatus} = this.state;
        let renderStartStop = () => {
            if (countdownStatus !== 'stopped') {
                return <StartStop countdownStatus={countdownStatus} onStatusChange={this.handleStatusChange()}/>
            } else {
                return <div>This will be the slider form</div>
            }
        };
        return(
            <div className={styles.container}>
                <p>This is the TeaTimer component</p>
                <Clock totalSeconds={count}/>
                {renderStartStop()}
            </div>
        )
    }
}

这是我的控件组件:

class StartStop extends Component {
    constructor(props) {
        super(props);
    }

    onStatusChange(newStatus) {
        return() => {
            this.props.onStatusChange(newStatus);
        }
    }

    render() {
        let {countdownStatus} = this.props;

        let renderStartStopButton = () => {
            if(countdownStatus === 'started') {
                return <button onClick={()=> this.onStatusChange('stopped')}>Reset</button>;
            } else {
                return <button onClick={()=> this.onStatusChange('started')}>Start</button>
            }
        };

        return(
            <div className={styles.tt.Controls}>
                {renderStartStopButton()}
            </div>
        )
    }
}

StartStop.propTypes = {
    countdownStatus: React.PropTypes.string.isRequired,
    onStatusChange: React.PropTypes.func.isRequired
};

对于文字墙我很抱歉,但我真的不知道错误来自哪里 - 因此不知道我可以省略代码的哪一部分。

我已尝试实施seemingly related question 中的解决方案,但也无法正常工作。

【问题讨论】:

  • 您可以尝试使用此行return &lt;StartStop countdownStatus={countdownStatus} onStatusChange={this.handleStatusChange}/&gt; 看看是否可以解决问题?
  • @FabianSchultz 这解决了我最初的问题:)

标签: javascript reactjs ecmascript-6


【解决方案1】:

return &lt;StartStop countdownStatus={countdownStatus} onStatusChange={this.handleStatusChange()}/&gt; 的这一行中给出警告,handleStatusChanged 函数在按下按钮时调用,该按钮试图通过 setState 关键字更改状态。每当状态更改时,都会再次调用渲染函数,但在您的情况下,渲染函数正在返回,而渲染函数又被 setState 关键字调用。

【讨论】:

    【解决方案2】:

    我认为你在这行有一个错字:

    return <StartStop countdownStatus={countdownStatus} onStatusChange={this.handleStatusChange()}/> 
    

    应该是:

    return <StartStop countdownStatus={countdownStatus} onStatusChange={() => this.handleStatusChange}/>
    

    您似乎在调用方法 handleStatusChange 而不是将其作为回调传递。

    【讨论】:

    • onStatusChange={this.handleStatusChange}
    【解决方案3】:

    您的方法相互调用,因此您必须定义您的方法的两个实例。

    class StartStop extends Component {
        constructor(props) {
            super(props);
            this.onStatusChangeReset=this.onStatusChange.bind(this);
            this.onStatusChangeStart=this.onStatusChange.bind(this);
    
        }
    
        onStatusChange(newStatus) {
            return() => {
                this.props.onStatusChange(newStatus);
            }
        }
    
        render() {
            let {countdownStatus} = this.props;
    
            let renderStartStopButton = () => {
                if(countdownStatus === 'started') {
                    return <button onClick={this.onStatusChangeReset('stopped')}>Reset</button>;
                } else {
                    return <button onClick={this.onStatusChangeStart('started')}>Start</button>
                }
            };
    
            return(
                <div className={styles.tt.Controls}>
                    {renderStartStopButton()}
                </div>
            )
        }
    }
    
    StartStop.propTypes = {
        countdownStatus: React.PropTypes.string.isRequired,
        onStatusChange: React.PropTypes.func.isRequired
    };
    

    【讨论】:

      猜你喜欢
      • 2017-12-20
      • 2016-09-20
      • 2016-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-22
      • 1970-01-01
      • 2017-09-04
      相关资源
      最近更新 更多