我在本地存储中持久化状态时遇到了问题。这是一个简单的待办事项应用程序。添加一个待办事项并刷新后,所有待办事项都会被删除。不知道为什么。以下是相关代码:
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
,然后在第二个useEffect
中调用todos
状态,不确定todos
状态是否更新。
useEffect
也将在组件渲染后第一次触发,即使它有依赖项(在你的情况下,它是[todos]
)。
对于一个可能的修复,您应该添加一个条件来检查todos
状态,然后在第二个useEffect
中再次更新它。
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])
您实现的那些副作用不适合delete-all情况。所以我想提出两个解决方案
第一个解决方案是使用另一个状态来跟踪第一次加载和下一次加载(如调用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")
}