编程 如何通过封装自定义Hook来实现对localStorage的响应式监听,解决了在更改时区时相关组件无法实时更新的问题

2024-11-19 03:08:13 +0800 CST views 771

响应式监听 localStorage 存储?封装个自定义 Hook 不就好了!

背景

项目中有一个全局更改时区的组件,同时还有一个局部更改时区的组件。需求是当更改时区时,所有相关组件能够实时联动并更新。

其实每次设置完时区的数据之后是存储在前端的 localStorage 中,组件也是从 localStorage 中获取默认值并显示。如果当前页面不刷新,时间组件就无法更新到最新的 localStorage 数据。那么,如何让 localStorage 存储的数据变成响应式呢?

实现

为了解决这一问题,我们可以编写一个公共的自定义 Hook,这样不仅仅是时区数据,其他需要监听 localStorage 变化的数据也可以复用这一逻辑。

失败的案例 1

一开始尝试使用 useEffect 监听 localStorage 变化:

useEffect(()=>{ 
    console.log(11111, localStorage.getItem('timezone')); 
},[localStorage.getItem('timezone')])

测试结果失败。原因是 localStorage.getItem('timezone') 在每次渲染时都会重新计算,导致无法正确监听到变化。

失败的案例 2

接下来尝试使用 windowstorage 事件来监听 localStorage 变化:

// useRefreshLocalStorage.js
import { useState, useEffect } from 'react';

const useRefreshLocalStorage = (key) => {
  const [storageValue, setStorageValue] = useState(localStorage.getItem(key));
  
  useEffect(() => {
    const handleStorageChange = (event) => {
      if (event.key === key) {
        setStorageValue(event.newValue);
      }
    };

    window.addEventListener('storage', handleStorageChange);

    return () => {
      window.removeEventListener('storage', handleStorageChange);
    };
  }, [key]);
  
  return [storageValue];
};

export default useRefreshLocalStorage;

然而,这种方式也失败了,因为 storage 事件只能监听同源的两个页面之间的 localStorage 变化,无法监听同一个页面的变化。

成功的案例

最终的解决方案是重写 localStorage.setItem 方法,通过触发自定义事件来实现响应式监听。

import { useState, useEffect } from "react";

function useRefreshLocalStorage(localStorage_key) {
  if (!localStorage_key || typeof localStorage_key !== "string") {
    return [null];
  }
  
  const [storageValue, setStorageValue] = useState(localStorage.getItem(localStorage_key));

  useEffect(() => {
    const originalSetItem = localStorage.setItem;

    localStorage.setItem = function(key, newValue) {
      const setItemEvent = new CustomEvent("setItemEvent", { detail: { key, newValue } });
      window.dispatchEvent(setItemEvent);
      originalSetItem.apply(this, [key, newValue]);
    };

    const handleSetItemEvent = (event) => {
      if (event.detail.key === localStorage_key) {
        setStorageValue(event.detail.newValue);
      }
    };

    window.addEventListener("setItemEvent", handleSetItemEvent);

    return () => {
      window.removeEventListener("setItemEvent", handleSetItemEvent);
      localStorage.setItem = originalSetItem;
    };
  }, [localStorage_key]);

  return [storageValue];
}

export default useRefreshLocalStorage;

使用示例

封装一个用于管理时区数据的自定义 Hook:

// useTimezone.js
import { useState, useEffect } from "react";
import { getTimezone, timezoneKey } from "@/utils/utils";
import useRefreshLocalStorage from "./useRefreshLocalStorage";

function useTimezone() {
  const [TimeZone, setTimeZone] = useState(() => getTimezone());
  const [storageValue] = useRefreshLocalStorage(timezoneKey);

  useEffect(() => {
    setTimeZone(() => getTimezone());
  }, [storageValue]);

  return [TimeZone];
}

export default useTimezone;

在业务页面组件中使用:

// 页面中
import useTimezone from "@/hooks/useTimezone";

export default (props) => {
  const [TimeZone] = useTimezone();
  
  useEffect(() => { 
    console.log(11111, TimeZone); 
  }, [TimeZone]);
};

测试结果是成功的!

小结

其实,使用全局 store 状态管理也可以达到同样的效果,正所谓“条条大路通罗马”。不过,由于历史原因,这次需求是使用 localStorage 来存储数据,因此我们通过封装自定义 Hook 实现了 localStorage 数据的响应式更新。


复制全文 生成海报 前端开发 React 状态管理 Hooks

推荐文章

Vue 3 中的 Fragments 是什么?
2024-11-17 17:05:46 +0800 CST
Redis和Memcached有什么区别?
2024-11-18 17:57:13 +0800 CST
介绍Vue3的Tree Shaking是什么?
2024-11-18 20:37:41 +0800 CST
js函数常见的写法以及调用方法
2024-11-19 08:55:17 +0800 CST
HTML和CSS创建的弹性菜单
2024-11-19 10:09:04 +0800 CST
Vue3中的Scoped Slots有什么改变?
2024-11-17 13:50:01 +0800 CST
nuxt.js服务端渲染框架
2024-11-17 18:20:42 +0800 CST
js迭代器
2024-11-19 07:49:47 +0800 CST
404错误页面的HTML代码
2024-11-19 06:55:51 +0800 CST
thinkphp swoole websocket 结合的demo
2024-11-18 10:18:17 +0800 CST
利用图片实现网站的加载速度
2024-11-18 12:29:31 +0800 CST
智能视频墙
2025-02-22 11:21:29 +0800 CST
JavaScript设计模式:装饰器模式
2024-11-19 06:05:51 +0800 CST
JavaScript 的模板字符串
2024-11-18 22:44:09 +0800 CST
【SQL注入】关于GORM的SQL注入问题
2024-11-19 06:54:57 +0800 CST
介绍Vue3的静态提升是什么?
2024-11-18 10:25:10 +0800 CST
JavaScript 实现访问本地文件夹
2024-11-18 23:12:47 +0800 CST
程序员茄子在线接单