前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >在 localStorage 中持久化 React 状态

在 localStorage 中持久化 React 状态

作者头像
Jimmy_is_jimmy
发布2023-04-22 19:48:34
3K0
发布2023-04-22 19:48:34
举报
文章被收录于专栏:call_me_R

原文链接 Persisting React State in localStorage -- 作者 Joshua Comeau

我们将创建一个日历应用,就像谷歌日历。这个应用可以让我们在月份、周和日之间进行切换。

于我个人而言,我经常看版面。它让我知道当天的所有事情,并且可以看到接下来几天的要发生什么事情。

值得庆幸的是,日历应用知道用户对这类事情有强烈的偏好,并且切换是“可记忆的(sticky)”。如果我从切换到,并刷新页面,视图是新的默认视图。

在本教程中,我们将了解如何创建自定义 React 钩子,来编写信息保存本地功能,以便我们在需要时使用它。

展示代码

我们自定义的钩子函数如下:

代码语言:javascript
复制
function useStickyState(defaultValue, key) {
  const [value, setValue] = React.useState(() => {
    const stickyValue = window.localStorage.getItem(key);
    
    return stickyValue !== null ? JSON.parse(stickyValue) : defaultValue;
  });
  
  React.useEffect(() => {
    window.localStorage.setItem(key, JSON.stringify(value));
  });
  
  return [value, setValue];
}

⚠️ SSR 呢? 如果你的应用是服务端渲染(使用框架比如 Next.js 或者 Gatsby),如果你尝试使用该钩子函数,你将会得到一个错误。 这实际上是一个很棘手的问题,因为 SSR 第一次渲染无法访问你浏览器上的 localStorage;它不可能知道初始值应该是什么。 在服务端渲染的应用中,动态内容是一个复杂的课题。但是,我为该课题写了一篇文章。若想了解更多,请前往 The Perils of Rehydration

为了演示它是怎么工作的,这里有个固定记数的记数器应用。我们可以尝试点击按钮多次,然后刷新页面。

如果这些代码你看不懂,没关系。本教程接下来会详细解析。💫

实战

这个钩子函数做了一个单一的假设,这在 React 应用程序中是相当安全的:表单输入值保存在 React 的状态(state)中。

这里有个表单非固定值的实现,控制不同值之间切换:

代码语言:javascript
复制
const CalendarView = () => {
  const [mode, setMode] = React.useState('day');
  
  return (
    <>
      <select onchange={ ev => setMode(ev.target.value)}>
        <option value="day">Day</option>
        <option value="week">Week</option>
        <option value="month">Month</option>
      </select>
      
      {/* Calendar stuff here */}
    </>
  )
}

我们可以使用刚才创建的新钩子函数,替换上面的钩子函数。

代码语言:javascript
复制
const CalendarView = () => {
  const [mode, setMode] = useStickyState('day', 'calendar-view');
    
  // Everything else unchanged
}

useState 钩子函数只需要传递一个参数,即其初始值。而 useStickyState 钩子函数传递两个参数,第一个参数也是初始值。第二个参数是我们要设置或者获取 localStorage 键(key)值。你给定 key 的值需要唯一。

它怎么工作

基本上,useStickyState 这个钩子函数是 useState 的包装器。只是,它做了一些其他事。

延迟初始化

首先,它发挥了延迟初始化的优势。这使得我们可以给 useState 传递一个函数,而不是一个值。当状态 state 被创建时,这个函数只是在组件第一次渲染被执行。

代码语言:javascript
复制
const [value, setValue] = React.useState(() => {
  const stickyValue =
    window.localStorage.getItem(key);
  return stickyValue !== null
    ? JSON.parse(stickyValue)
    : defaultValue;
});

在我们的案例中,我们使用它来检查 localStorage 中的值。如果值存在,我们将使用该值作为我们的初始值。否则,我们将使用钩子函数传递的默认值(在我们先前的例子中,其默认值是 day)。

保持 localStorage 同步

最后一步,确保当我们更改 state 中的值,需要更新 localStorage 。为此,我们可信赖的伙伴 useEffect 派上用场:

代码语言:javascript
复制
React.useEffect(() => {
  window.localStorage.setItem(name, JSON.stringify(value));
}, [name, value]);

⚠️ 频繁更新? 如果 state 状态值更改太快(比如,一秒中执行很多次),你可能需要使用节流 throttle 或者防抖 debounce 来更新 localStorage。因为 localStorage 是一个同步 API,如果它更新太频繁,会造成性能问题。 不过,不要以此为借口过早优化。分析器 Profiler 会向你展示是否需要限制更新。

总结

这个钩子函数是一个小而强大的例子,说明自定义钩子如何让我们为解决问题而发明自己的 API。虽然存在帮我们解决这个问题的依赖包,但是我认为了解如何解决这些问题很有价值。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-04-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 展示代码
  • 实战
  • 它怎么工作
    • 延迟初始化
      • 保持 localStorage 同步
      • 总结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档