javascript 为什么localStorage在重新加载页面后不使状态持久化?

gorkyyrv  于 5个月前  发布在  Java
关注(0)|答案(3)|浏览(56)

我遵循this教程在React中使用localStorage:

import { useState, useEffect } from 'react';

function App() {
  // In the original code, this is inside the `useVolume` hook
  const [volumes, setVolumes] = useState([0, 0, 0]);

  useEffect(() => {
    const savedVolumes = localStorage.getItem('volumes');

    if (savedVolumes) {
      const parsedVolumes = JSON.parse(savedVolumes);
      setVolumes(parsedVolumes);
    }
  }, []);

  useEffect(() => {
    localStorage.setItem('volumes', JSON.stringify(volumes));
  }, [volumes]);

  // In the original code, this is inside the `useVolume` hook
  // with other functions that update `volumes`
  const updateVolumes = () => {
    const newVolumes = [0, 0, 1];
    setVolumes(newVolumes);
  };

  return (
    <div className="App">
      <div>{JSON.stringify(volumes)}</div>
      <button onClick={updateVolumes}>Update Volumes</button>
    </div>
  );
}

export default App;

字符串
当我按下Update Desktop按钮时,volumes localStorage更改为[0, 0, 1],但当我重新加载页面时,卷又回到[0, 0, 0](localStorage也回到[0, 0 ,0])。
如何更改此代码,使volumeslocalStorage即使在重新加载页面后也是[0, 0, 1]
Live code at StackBlitz
注意事项:为了简化示例,我将volumessetVolumesupdateVolumes放在App()中。在原始应用中,它们位于hook中。这就是为什么我将localStorage从它们的逻辑中解耦。我认为将其与钩子分开会更好地分离关注点。

ffdz8vbo

ffdz8vbo1#

我不认为你跟踪的文章在这里真的给出了好的建议。
这里的第一个错误是,useEffect不是必需的。使用useEffect通常有两个原因。要么是async需要发生,因为React客户端是syncuseEffect很方便,另一个原因可能是使用ref访问DOM元素。这两个标准都不适用于您试图解决的问题。
另一个错误是认为useEffect的行为就像某种状态更改事件,例如。如果某些状态更改,则运行此代码。不,这不是它的目的。我知道它看起来像那样,所以很容易犯错误。根据某些状态更新来更新状态效果实际上是自找麻烦。
因此,在考虑了所有这些因素之后,您的代码可以像->一样简单。

import { useState } from 'react';

function App() {
  const [volumes, setVolumes] = useState(
    () => JSON.parse(localStorage.getItem('volumes') ?? '[0,0,0]'));

  const updateVolumes = () => {
    const newVolumes = [0, 0, 1];
    localStorage.setItem('volumes', JSON.stringify(newVolumes));
    setVolumes(newVolumes);
  };

  return (
    <div className="App">
      <div>{JSON.stringify(volumes)}</div>
      <button onClick={updateVolumes}>Update Volumes</button>
    </div>
  );
}

export default App;

字符串
注意,在上面我还使用了useState的回调版本,原因是我们只需要在挂载时从localeStorage加载,没有它也可以工作,但是从localeStorage加载没有意义,因为它只是被忽略,因为后续渲染的状态无论如何都不会使用初始值。

vc9ivgsu

vc9ivgsu2#

让我们浏览一下你的代码,你会看到为什么会发生这种情况。你将默认状态设置为[0,0,0]在挂载时,useEffect将基本上运行本地存储中的任何内容。你可以这样做

const savedVolumes = localStorage.getItem("volumes");
  const [volumes, setVolumes] = useState(JSON.parse(savedVolumes) ?? [0, 0, 0]);

字符串
如果本地存储为空,则仅有条件地设置默认值

pod7payv

pod7payv3#

原因是因为您使用的是
在严格模式下,react运行你的组件两次,这会导致在localstorge中重置音量。

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
)

字符串
删除严格模式,它将开始按预期工作。但是,当你设计你的组件时,要确保无论调用多少次,结果都是一样的。
我建议你阅读文档,而不是那些旧的教程。https://react.dev/reference/react/useEffect
更新
您不需要第二次使用效果。我们确切地知道卷何时更新。因此只需将其保存在eventhandler中

const updateVolumes = () => {
    const newVolumes = [0, 0, 1];
    setVolumes(newVolumes);
    localStorage.setItem('volumes', JSON.stringify(newVolumes));
  };


注意,我使用的是newVolumes而不是volumes,因为setVolumes并不更新状态,只是安排了一个稍后的更新,所以volumes仍然保持着旧的状态。
查看更多信息-https://react.dev/learn/you-might-not-need-an-effect

相关问题