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

Avoiding `setTimeout` 'hack' to ensure state is in sync

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

作为奖励功能,该列表会在用户修改后保存到 localStorage,并在组件的初始安装时使用。

addTodoremoveTodo方法中,模式都是这样的:

  1. 通过添加或删除 this.state.todos
  2. 的项目来设置新状态
  3. 复制状态到localStorage

例如,这里是 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 总是落后 1 步,使用的是用户可能认为是过时版本的列表。

这感觉像是黑客攻击。如何在不使用 setTimeout hack 的情况下合并做同样事情的方法?

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

setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.

There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.

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));