避免`setTimeout`'hack'以确保状态同步

时间:2016-11-19 23:50:15

标签: javascript reactjs state

我使用React编写了一个小型todo应用程序,用户可以在其中添加和删除项目列表。

作为奖励功能,该列表会保存到localStorage,因为它已被用户变更,并在组件的初始安装时使用。

addTodoremoveTodo方法中,模式如下:

  1. 通过添加或删除this.state.todos
  2. 项来设置新状态
  3. 将状态复制到localStorage
  4. 例如,这是removeTodo方法:

    removeTodo(indexOfItemToRemove) {
        const todosCopy = this.state.todos.slice();
    
        todosCopy.splice(indexOfItemToRemove, 1);
    
        this.setState({
            todos: todosCopy
        });
    
        this.updateLocalStorageWithState();
    }
    

    以下是我目前要将this.state.todos保存到localStorage

    的内容
    updateLocalStorageWithState() {
        setTimeout(() => {
            localStorage.setItem('localStorageTodos', JSON.stringify(this.state.todos));
        }, 1);
    }
    

    我发现在不使用setTimeout的情况下,localStorage总是落后一步,使用用户可能认为是列表过期版本的内容。

    这感觉就像一个黑客。如何在不使用setTimeout hack的情况下采用相同的方法进行操作?

1 个答案:

答案 0 :(得分:2)

setState()不一定是同步执行的。这会导致您遇到的行为:

  

setState()不会立即改变this.state,但会创建待处理状态转换。在调用此方法后访问this.state可能会返回现有值。

     

无法保证对setState的调用进行同步操作,并且可以对调用进行批处理以获得性能提升。

Source

幸运的是,setState()接受第二个参数,这是在状态更新完成时调用的回调。您可以使用它来同步本地存储条目:

this.setState({
    todos: todosCopy
}, () => {
    localStorage.setItem('localStorageTodos', JSON.stringify(this.state.todos));
});

或者,为什么不直接设置本地存储条目而不是先从state读取?

this.setState({
    todos: todosCopy
});

localStorage.setItem('localStorageTodos', JSON.stringify(todosCopy));