为什么要删除 localStorage 中的 React 状态

Why React state in localStorage is being deleted

我在将状态保存在本地存储中时遇到问题。这是一个简单的待办事项应用程序。添加一个待办事项并刷新后,所有待办事项都被删除了。不知道为什么。相关代码如下:

const [ todos, setTodos ] = useState([])
      useEffect(() => {                                                                                                         
  │   │   console.log('b1:',JSON.parse(localStorage.todos))                                                                     
  │   │   if (localStorage.todos !==null) {                                                                                     
  │   │   │   console.log(JSON.parse(localStorage.todos))                                                                       
  │   │   │   setTodos(JSON.parse(localStorage.todos))                                                                          
  │   │   }                                                                                                                     
  │   │   console.log('a1:',JSON.parse(localStorage.todos))                                                                     
  │   }, [])                                                                                                                    
  │   useEffect(() => {                                                                                                         
  │   │   // if (todos.length > 0) {                                                                                            
  │   │   │   console.log('b2:',JSON.parse(localStorage.todos))                                                                 
  │   │   │   localStorage.setItem("todos", JSON.stringify(todos))                                                              
  │   │   │   console.log('a2:',JSON.parse(localStorage.todos))                                                                 
  │   │   // }                                                                                                                  
  │   }, [todos])     

控制台输出(b1 before1,a1 after1 等):

[Log] b1: – [{text: "one", done: false, id: "6c570584b1a"}] (1)
[Log] [{text: "one", done: false, id: "6c570584b1a"}] (1)
[Log] a1: – [{text: "one", done: false, id: "6c570584b1a"}] (1)
[Log] b2: – [{text: "one", done: false, id: "6c570584b1a"}] (1)
[Log] a2: – [] (0)
[Log] b1: – [] (0)
[Log] [] (0)
[Log] a1: – [] (0)
[Log] b2: – [] (0)
[Log] a2: – [] (0)
[Log] b2: – [] (0)
[Log] a2: – [] (0)

useState 钩子是异步的。根据您的代码,您在第一个 useEffect 中调用 setTodos,然后在不确定 todos 状态是否更新的第二个 useEffect 中调用 todos 状态。

useEffect 也会在组件渲染后第一次触发,即使它有依赖关系(在你的情况下,它是 [todos])。

对于可能的修复,您应该在第二次 useEffect.

中再次更新之前添加一个条件来检查 todos 状态
useEffect(() => {                                                                                                         
        console.log('b1:',JSON.parse(localStorage.todos))                                                                     
        if (localStorage.todos !==null) {                                                                                     
           console.log(JSON.parse(localStorage.todos))                                                                       
           setTodos(JSON.parse(localStorage.todos))                                                                          
        }                                                                                                                     
        console.log('a1:',JSON.parse(localStorage.todos))                                                                     
     }, [])                                                                                                                    
     useEffect(() => {                                                                                                         
        if (todos && todos.length > 0) {                                                                                            
           console.log('b2:',JSON.parse(localStorage.todos))                                                                 
           localStorage.setItem("todos", JSON.stringify(todos))                                                              
           console.log('a2:',JSON.parse(localStorage.todos))                                                                 
        }                                                                                                                  
     }, [todos])  

您实施的 side-effects 不适用于 delete-all 案例。所以我会提出 2 个解决方案

第一个解决方案是使用另一个状态来跟踪第一次加载和下一次加载(比如调用 API)

const [isLoaded, setIsLoaded] = useState(false)
useEffect(() => {                                                                                                         
        console.log('b1:',JSON.parse(localStorage.todos))                                                                     
        if (localStorage.todos !==null) {                                                                                     
           console.log(JSON.parse(localStorage.todos))                                                                       
           setTodos(JSON.parse(localStorage.todos)) 
           setIsLoaded(true)                                                                         
        }                                                                                                                     
        console.log('a1:',JSON.parse(localStorage.todos))                                                                     
     }, [])                                                                                                                    
     useEffect(() => {                                                                                                             
           if(isLoaded) {
              console.log('b2:',JSON.parse(localStorage.todos))                                                                 
              localStorage.setItem("todos", JSON.stringify(todos))                                                              
              console.log('a2:',JSON.parse(localStorage.todos)) 
           }                                                                                             
     }, [todos, isLoaded])  

第二个解决方案是在 deleteAll 中更新 localStorage 而不是

useEffect(() => {                                                                                                         
        console.log('b1:',JSON.parse(localStorage.todos))                                                                     
        if (localStorage.todos !==null) {                                                                                     
           console.log(JSON.parse(localStorage.todos))                                                                       
           setTodos(JSON.parse(localStorage.todos))                                                                          
        }                                                                                                                     
        console.log('a1:',JSON.parse(localStorage.todos))                                                                     
     }, [])                                                                                                                    
     useEffect(() => {                                                                                                         
        if (todos && todos.length > 0) {                                                                                            
           console.log('b2:',JSON.parse(localStorage.todos))                                                                 
           localStorage.setItem("todos", JSON.stringify(todos))                                                              
           console.log('a2:',JSON.parse(localStorage.todos))                                                                 
        }                                                                                                                  
     }, [todos])  

function deleteAll() {
   setTodos(null)
   localStorage.removeItem("todos")  
}