用 9 行代码保存你的 React 状态

2025-06-07

用 9 行代码保存你的 React 状态

这周末我正在研究Frontend Mentor的一个项目,并用 React Hooks 实现了主题切换器。我突然想到,在每次重新加载时保留我选择的主题会是一个很棒的功能。所以,让我们来构建一个可以实现这个功能的 Hooks 吧!

本文将带您完成创建可重用自定义钩子的过程,该钩子将我们的状态保存到本地存储。

入门

我们将创建一个名为 的自定义钩子,用于usePersistedState将状态存储到本地存储。我们的函数应该接受一个键来存储状态,以及一个默认值(以防我们尚未保存任何内容)。它将返回相同的 API useState(一个包含状态和更新函数的元组)。以下是我们的钩子签名:

function usePersistedState(key, defaultValue) {
  // Some magic
  return [state, setState];
}
Enter fullscreen mode Exit fullscreen mode

即使我们将状态存储在本地存储中,我们也会在常规setState调用中保留本地运行时副本。这样我们就可以触发重新渲染,并稍微缩短访问时间(访问本地存储可能没那么快)。最后,如果 localStorage 由于某种原因不可用,我们仍然有一个可用的钩子(尽管它不会持久化设置)。

function usePersistedState(key, defaultValue) {
  const [state, setState] = React.useState(defaultValue);
  return [state, setState];
}
Enter fullscreen mode Exit fullscreen mode

将数据保存在本地存储中

接下来,让我们开始从本地存储读取数据!该localStorageAPI 内置于您的浏览器中,您可以通过getItem使用字符串键调用函数来访问值。

function usePersistedState(key, defaultValue) {
  const [state, setState] = React.useState(
    localStorage.getItem(key) || defaultValue
  );
  return [state, setState];
}
Enter fullscreen mode Exit fullscreen mode

在这里,我们将调用的默认值设置useState为 localStorage 中存储的内容,或者defaultValue我们作为参数传入的内容。接下来,让我们实现更新本地存储的功能。我们将使用一个useEffect钩子来实现这一点:

function usePersistedState(key, defaultValue) {
  const [state, setState] = React.useState(
    localStorage.getItem(key) || defaultValue
  );
  useEffect(() => {
    localStorage.setItem(key, state);
  }, [key, state]);
  return [state, setState];
}
Enter fullscreen mode Exit fullscreen mode

很聪明吧?每次更新状态时,都应该更新本地存储中的内容。如果键发生变化,我们也应该将当前状态存储在新的键下。

那么复数值呢?

虽然本地存储 API 很棒,但它只能存储字符串值。这有点麻烦——但我们可以通过在更新状态时将 JavaScript 对象序列化为 JSON(并返回)来绕过这个限制。我们使用JSON.parseJSON.stringify函数来实现。

function usePersistedState(key, defaultValue) {
  const [state, setState] = React.useState(
    JSON.parse(localStorage.getItem(key)) || defaultValue
  );
  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(state));
  }, [key, state]);
  return [state, setState];
}
Enter fullscreen mode Exit fullscreen mode

现在我们也支持复杂的数据结构!

最后的性能优化

我们目前的实现有一个性能陷阱——每次渲染都要从本地存储读取!更糟糕的是——我们这样做只是为了获取调用的初始值useState!幸运的是,有办法解决这个问题。通过传入一个函数useState,默认值只会运行一次!

让我们来实现它:

function usePersistedState(key, defaultValue) {
  const [state, setState] = React.useState(
    () => JSON.parse(localStorage.getItem(key)) || defaultValue
  );
  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(state));
  }, [key, state]);
  return [state, setState];
}
Enter fullscreen mode Exit fullscreen mode

总结!

就这样!我们用几行代码实现了一段非常简洁的可复用代码。这非常适合用于本地设置,例如主题、字体大小,或者您希望在访问之间保留的其他 UI 状态。

这就是我最初提到的项目,它包含一个用于保存所选主题的钩子。快来试试吧!

最喜欢的可重复使用的挂钩是什么

文章来源:https://dev.to/selbekk/persisting-your-react-state-in-9-lines-of-code-9go
PREV
您应该关注的两个媒体查询
NEXT
如何阻止旋转器在 React 中跳动