首页 > 解决方案 > React Hooks LocalStorage setState 覆盖元素

问题描述

在将任务存储在本地存储中的情况下,我正在使用 useEffect 处理 React 钩子,因此刷新页面仍将处理列表中的元素。问题是当我试图从 LocalStorage 获取元素并将它们设置为 todos 状态时。它们存在于 localStorage 中,但 todos 状态中的元素只是 localstorage 中的一个。

这是一个处理此问题的组件:

  const [todos, setTodos] = useState([]);
  const [todo, setTodo] = useState("");

  const addTask = (event) => {
    event.preventDefault();
    let newTask = {
      task: todo,
      id: Date.now(),
      completed: false,
    };
    setTodos([...todos, newTask]);
    setTodo("");
  };
  
    const getLocalStorage = () => {
      for (let key in localStorage) {
        if (!localStorage.hasOwnProperty(key)) {
          continue;
        }
        let value = localStorage.getItem(key);
        try {
          value = JSON.parse(value);
          setTodos({ [key]: value });
        } catch (event) {
          setTodos({ [key]: value });
        }
      }
    };
  
    const saveLocalStorage = () => {
      for (let key in todos) {
        localStorage.setItem(key, JSON.stringify(todos[key]));
      }
    };
  
    useEffect(() => {
      getLocalStorage();
    }, []);
  
    useEffect(() => {
      saveLocalStorage();
    }, [saveLocalStorage]);
  
    const testClick = () => {
      console.log(todos);
    };
return (
    <div className="App">
      <h1>What would you like to do?</h1>
      <TodoForm
        todos={todos}
        value={todo}
        inputChangeHandler={inputChangeHandler}
        addTask={addTask}
        removeCompleted={removeCompleted}
      />

      {/* <TodoList todos={todos} toogleCompleted={toogleCompleted} /> */}
      <button onClick={testClick}>DISPLAY TODOS</button>
    </div>
  ); 

todos状态控制台

本地存储部分

刷新页面时的第二个问题错误:

新错误

除此之外,从本地存储中获取元素后,我无法显示它们。可能我错过了一些愚蠢的小东西,但我停留在这一刻,我想知道是否可以在我犯错误的地方进行小的解释。

标签: reactjsreact-hookslocal-storage

解决方案


我认为您正在一起覆盖状态值。您想附加到待办事项状态中存在的内容。您可以使用扩展运算符将待办事项设置为已经存在的所有内容以及新值。

像这样的东西:

setTodos({...todos, [key]: value });

setTodos([...todos,  [key]: value ]);
  • 请注意,扩展运算符是一个浅克隆。如果您有更深的对象(我认为超过两层),那么请使用 lodash 库中的 cloneDeep 之类的东西。

要查看发生了什么,请更改此块以添加 console.logs

try {
  value = JSON.parse(value);
  setTodos({ [key]: value });
  console.log(todos);

} catch (event) {
  console.log('There was an error:', error);
  // Should handle the error here rather than try to do what failed again
  //setTodos({ [key]: value });
}

编辑:关于您添加的错误。

您正在尝试在对象上使用地图。map 是一个数组函数。

相反,您会将对象转换为数组,然后返回:

const myObjAsArr = Object.entries(todos).map(([k,v]) => {
    // Do stuff with key and value
}
const backToObject = Object.fromEntries(myObjAsArr);

更改此项以设置数组(不是对象):

setTodos([...todos,  [key]: value ]);

将控制台日志放在任何地方,这样您就可以看到发生了什么。


推荐阅读