【问题标题】:setState is not updating the state by the time the Flux Store action is calledsetState 在调用 Flux Store 操作时没有更新状态
【发布时间】:2016-06-02 01:29:13
【问题描述】:

我有 2 个组件。一个项目容器和一个项目设置面板(以后会有更多项目设置面板)。

我在面板中有一个开关,调用“switchSubmit”函数来更新状态,然后调用“handleSubmit”函数,该函数包含一个根据 Switch Button 的值更新 Flux Store 的操作,我正在设置状态,但是它似乎总是在调用我的操作时选择的先前值。

我读到 setState 不是同步的,我也看过一些示例,但不知道如何应用正确的调用和函数来设置状态,并在调用此特定操作时准备好更新的状态以供使用我正在编写的代码。

这是我的代码:

var React = require('react/addons');
var Actions = require('../../Actions');
var ConfigurationStore = require('../../stores/Configuration');

var Controller = React.createClass({
    getInitialState: function () {

        ConfigurationStore.reset();

        Actions.getConfigurationSettings();

        return this.getStateFromStores();
    },

    getStateFromStores: function () {
        return {
            configuration: ConfigurationStore.getState()
        };
    },

    componentDidMount: function () {
        ConfigurationStore.addChangeListener(this.onStoreChange);
    },

    componentWillUnmount: function () {
        ConfigurationStore.removeChangeListener(this.onStoreChange);
    },

    onStoreChange: function () {
        this.setState(this.getStateFromStores());
    },


    render: function () {

        return (
            <section className="section-settings container">
                <h1 className="page-header">Projects</h1>
                <div className="row">
                    <div className="col-sm-12">
                        <div className="row">
                            <div className="col-sm-3">
                            </div>
                            <div className="col-sm-9">
                                <h2>Project Settings</h2>
                                <hr />
                                <ProjectContainer data={this.state.configuration} />
                            </div>
                        </div>
                    </div>
                </div>
            </section>
        );

    }

});    


var ProjectContainer = React.createClass({

    getInitialState: function () {
        return {
            active: false

        };
    },

    componentWillReceiveProps: function (nextProps) {
        this.setState({
            active: nextProps.data.active
        });
    },

    render: function () {
        return (
            <div>
                <ProjectPanel data={this.props.data}></ProjectPanel>
            </div>
        );

    }
});


var ProjectPanel = React.createClass({

    getInitialState: function () {
        return {
            active: false
        };
    },

    componentWillReceiveProps: function (nextProps) {
        this.setState({
            active: nextProps.data.active
        });
    },

    handleSubmit: function () {
        Actions.updateConfigurationSettings({
            active: this.state.active
        });
    },

    switchSubmit: function(event) {
        event.stopPropagation();

        this.setState({
            active: event.currentTarget.checked
        });

        this.handleSubmit();

    },

    render: function() {

        var formElements = (
                <fieldset>
                    <SwitchButton
                        name="switch-1"
                        onChange={this.switchSubmit}
                        checked={this.props.active}
                    />
                </fieldset>
            );
        }

        return (
            <div className="project-holder">
                <div className="project-config">
                    <form onSubmit={this.handleSubmit}>
                        {formElements}
                    </form>
                </div>
            </div>
        );
    }
});

任何帮助将不胜感激!

【问题讨论】:

    标签: javascript reactjs flux reactjs-flux


    【解决方案1】:

    为了直接回答您的问题,setState 接受一个回调,该回调可用于将代码延迟到渲染完成后。但是,您不需要在您的场景中使用它。

    我在您的代码中看到的问题是,对于“活动”状态,您有多个事实来源。

    我已更新您的代码以解决该问题:

    var React = require('react/addons');
    var Actions = require('../../Actions');
    var ConfigurationStore = require('../../stores/Configuration');
    
    var Controller = React.createClass({
        getInitialState: function () {
    
            ConfigurationStore.reset();
    
            Actions.getConfigurationSettings();
    
            return this.getStateFromStores();
        },
    
        getStateFromStores: function () {
            return {
                configuration: ConfigurationStore.getState()
            };
        },
    
        componentDidMount: function () {
            ConfigurationStore.addChangeListener(this.onStoreChange);
        },
    
        componentWillUnmount: function () {
            ConfigurationStore.removeChangeListener(this.onStoreChange);
        },
    
        onStoreChange: function () {
            this.setState(this.getStateFromStores());
        },
    
    
        render: function () {
    
            return (
                <section className="section-settings container">
                    <h1 className="page-header">Projects</h1>
                    <div className="row">
                        <div className="col-sm-12">
                            <div className="row">
                                <div className="col-sm-3">
                                </div>
                                <div className="col-sm-9">
                                    <h2>Project Settings</h2>
                                    <hr />
                                    <ProjectContainer data={this.state.configuration} />
                                </div>
                            </div>
                        </div>
                    </div>
                </section>
            );
    
        }
    
    });    
    
    var ProjectContainer = React.createClass({
        render: function () {
            return (
                <div>
                    <ProjectPanel data={this.props.data}></ProjectPanel>
                </div>
            );
    
        }
    });
    
    
    var ProjectPanel = React.createClass({
        handleSubmit: function () {
            // Do something interesting on submit.
        },
    
        switchSubmit: function(event) {
            event.stopPropagation();
            Actions.updateConfigurationSettings({
                active: event.target.checked
            });
        },
    
        render: function() {
    
            var formElements = (
                    <fieldset>
                        <SwitchButton
                            name="switch-1"
                            onChange={this.switchSubmit}
                            checked={this.props.data.active}
                        />
                    </fieldset>
                );
            }
    
            return (
                <div className="project-holder">
                    <div className="project-config">
                        <form onSubmit={this.handleSubmit}>
                            {formElements}
                        </form>
                    </div>
                </div>
            );
        }
    });
    

    无需在ProjectContainerProjectPanel 中保持本地状态。 “活动”状态通过 props 向下流向这些组件。

    我没有在您的handleSubmit 按钮中添加任何代码,因为我不认为您在其中的内容最初是有意义的。你只需要你想在提交时运行的任何代码。

    【讨论】:

    • 谢谢,这很有意义。我唯一不明白的是当您触发 Action.updateConfigurationSettings 时您用于 switchSubmit 的值不应该使用 switch 事件值而不是 !this.props.data.active 设置活动值?
    • 是的,你是对的。我使用的事实是它只是一个布尔值,所以我们知道它将与 this.props.active 在更改之前的任何内容相反。但是,从元素本身获取它更正确。我已经更新了我的答案。
    • 很棒的东西。我已经投票了!您的解释很容易理解,代码运行良好
    【解决方案2】:

    this.setState 允许回调函数,如果你需要在状态完全改变后做某事。

    语法应该是这样的:

    switchSubmit: function(event) {
        event.stopPropagation();
    
        this.setState({
            active: event.currentTarget.checked
        }, this.handleSubmit);
    
    
    
    },
    

    【讨论】:

      猜你喜欢
      • 2019-01-28
      • 2018-08-11
      • 1970-01-01
      • 2017-09-05
      • 2020-03-03
      • 1970-01-01
      • 2018-07-25
      • 2017-09-16
      相关资源
      最近更新 更多