【问题标题】:How do I update the state (using ReactJS) if I should not call setState in componentWillUpdate?如果我不应该在 componentWillUpdate 中调用 setState,我该如何更新状态(使用 ReactJS)?
【发布时间】:2015-05-10 18:59:22
【问题描述】:

当我在componentWillUpdatesetState 时,componentWillUpdate 在无限循环中运行,并且不会停止被触发。

这永远不会让我的render 有机会反映我的更改。如果我不应该使用componentWillUpdate,我该如何更改状态?

编辑:我已经有了一些理解,setState 不应该在 componentWillUpdate 中调用。我只是很困惑我应该做些什么作为替代方案。

编辑#2:我从componentWillReceiveProps 开始,但是当我的父组件更改状态时,我似乎无法触发此功能。我将来自父母的状态作为道具提供给我的孩子。

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    首先要做的是查看此方法的官方文档 (link)。当函数被实际调用时,你可以在哪里阅读。

    然后阅读常见错误(注):

    您不能在此方法中使用 this.setState()。如果您需要更新状态以响应 prop 更改,请改用 componentWillReceiveProps。

    你改变状态,React 会自动调用componentWillUpdate

    【讨论】:

    • 谢谢!我已经阅读了文档,但没有掌握触发 componentWillUpdate 的道具和状态的想法。实际上,我想调用 componentWillUpdate 是因为我从父母那里收到了新的道具。但是,我想在让我的数据渲染之前处理道具中的数据。这是否意味着我不需要调用 setState 直接操作道具?
    • @David,你会在将 children 安装到 dom 后更改它们吗?你不应该直接操作 props,因为它不会触发 props changed 事件。
    • 我有这样的事情:<div> <h1>This room is currently {this.props.roomId}</h1> <SongQueue queue={this.state.queue}/> <Search addSongToQueue={this.addSongToQueue}/> </div> this.state.queue 正在改变,但我的孩子SongQueue 似乎无法正确接收它。这是我的第一个主要父组件的render
    • 如果您无法解决此问题,您可以将您的问题作为新问题发布。抱歉,仅用 cmets 很难理解。
    • 请注意,大多数时候您可以直接使用道具,而不是将其设置为内部状态。您还可以在 render 方法中内联修改。这样可以省去很多麻烦。
    【解决方案2】:

    我知道在guide 中会警告这一点,但我不确定从componentWillUpdate 中调用setState 是否会出现问题。诚然,它可能会导致无限递归除非当然你提供了该递归的底部(一种打破它的方法)。例如。一种方法是检查componentWillUpdate 中的第二个(nextState)参数,如果满足某些条件(即递归结束时),则不再调用setState

    作为一个最小的例子,想象一个完全没有属性的组件,只有两个状态。进一步想象第二个状态是从第一个异步获得的。例如。第一个状态可以是提供给 Ajax 调用的一些参数,第二个状态是该调用的结果。所以基本上你调用this.setState 来配置参数,然后在componentWillUpdate 中你可以做如下的事情(为了简单起见,我使用window.setTimeout 作为Ajax 调用的占位符):

    const ComponentWithAsyncState = React.createClass({
        getInitialState: function() {
            return {
                ajaxParams: '',
                ajaxResult: ''
            };
        },
        setAjaxParams: function(params) {
            this.setState({ajaxParams: params});
        },
        componentWillUpdate: function(_, nextState) {
            if (nextState.ajaxParams!=this.state.ajaxParams)
                window.setTimeout(function imagineThisIsAjax() {
                    this.setState({ajaxResult: `result from ${nextState.ajaxParams}`});
                }.bind(this), 2000);
        },
    

    当(例如通过此组件管理的某些控件)ajaxParams 更改时,操作顺序将类似于(其中~~> 表示异步):

    setAjaxParams --> this.setState --> componentWillUpdate ~~> imagineThisIsAjax --> this.setState --> componentWillUpdate
    

    即对componentWillUpdate 的第二次调用不会导致进一步的this.setState,因此递归将在那里结束。

    【讨论】:

    • React 组件实际上应该只是显示给它的数据。这就是为什么他们引入了 Flux 来处理数据流,并且 react 只是显示它。在 componentWillUpdate 中有 this.setState() 会在视图层中尖叫业务逻辑,在您的示例中就是这种情况。当然,您可以随心所欲,而且它会起作用。但我相信你可以使用更好的工具(模式)来做到这一点,而不会有无限循环的风险。
    • 不推荐在 componentWillUpdate 上使用 setState,因为调用循环 (facebook.github.io/react/docs/…)
    • @the_bluescreen 我当然知道这一点,这就是为什么我谈到无限递归的可能性并注意,如果你提供递归的底部,你就不会遇到这个问题。显然您没有阅读答案或无法理解它。哦,谢谢你的链接,但它已经在我的回答中了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-23
    • 1970-01-01
    • 2020-01-30
    • 2022-01-16
    • 2018-12-08
    • 1970-01-01
    相关资源
    最近更新 更多