多个setState排队并导致一切都感觉缓慢

时间:2015-04-28 07:10:11

标签: javascript reactjs

我有一个带有4个按钮的ReactJS菜单组件,它触发我页面的右侧和一堆过滤器,以便在点击时重新加载。

render: function() {
    return (
        <div className="menu">
            {
                this.state.items.map(function(menuNode) {
                    return (
                        <MenuItem item={menuNode} onClick={this.handleClick} key={menuNode.name} />
                    );
                }, this)
            }
        </div>
    );
},
handleClick: function(selected) {
    this.state.items.forEach(function(item) {
        item.selected = false;
    });
    selected.selected = true;
    this.setState({
        items: this.state.items
    });

    resetReact.BoxStructure(selected);
    resetReact.Filter(selected);
}

resetReact.BoxStructure()resetReact.Filter()会触发setProps() / setState()我的页面中的新内容(BoxStructure)和过滤器组件。

它们在componentDidMount中设置在每个组件上,如下所示:

var BoxStructure = React.createClass({

    ...

    componentDidMount: function() {
        if(this.props.callback)
            this.props.callback();

        resetReact.BoxStructure = function(selected) {
            this.state.boxes = selected.content;
            this.setProps({
                color: selected.color,
                callback: selected.callback,
                key: selected.name
            });
        }.bind(this);
}
});

这样可行,但菜单感觉非常慢,就像它在更改所选菜单项之前等待整个页面加载一样。 BoxStructure需要几秒钟才能加载,这很好并且可以预期,但我不希望菜单在更改所选项目之前等待它。从用户的角度来看,当我点击按钮时感觉没有任何反应。

这可以通过添加setTimeout 1ms:

来解决
handleClick: function(selected) {
    this.state.items.forEach(function(item) {
        item.selected = false;
    });
    selected.selected = true;
    this.setState({
        items: this.state.items
    });
    setTimeout(function() {
        resetReact.BoxStructure(selected);
        resetReact.Filter(selected);
    }, 1);
}

现在菜单立即改变,然后页面可能需要渲染,就像我想要的那样,但问题是为什么我做了一些根本错误的事情?我认为setTimeout强制重新加载是异步的,但我觉得这不是实现我想要的正确方法,也许ReactJS在某个地方有更好的方法。

1 个答案:

答案 0 :(得分:3)

您应该努力提高BoxStructureFilter代码的效率。您可能想要对它们进行分析,打印毫秒时间戳,并执行其他此类操作。

如果您知道这些通话速度很慢,并且您希望向用户提供有关正在发生的事情的反馈,那么您可能希望延迟这些繁重的通话,直到上一次状态更新完成 并呈现

这样做的方法是使用setState的回调:

handleClick: function(selected) {
    ...
    this.setState({
        items: ...
    }, function() {
        resetReact.BoxStructure(selected);
        resetReact.Filter(selected);
    });
}

来自文档:

  

第二个(可选)参数是一个回调函数,该函数将在setState完成 并且重新呈现组件 后执行。

同样来自文档:

  

不要直接改变this.state,因为之后调用setState()可能会替换你所做的突变。把this.state看作是不可变的。

你通过改变this.state然后将它反馈给setState()来避开罚款线。不要那样做。

作为替代方案,您可以在您的州中存储单个selected索引(0到selectedItem - 1之间的整数),而不是在每个项目中存储items.length标志。您只需要更新该单个变量。

此外,为什么您的菜单项目处于开始状态?用户是否允许更改它们?如果答案是否定的,那么你应该将它们放在道具或类常量中。