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

 

背景

项目上有个更改时区的全局组件,同时还有一个可以更改时区的局部组件,想让更改时区的时候能联动起来,实时响应起来

其实每次设置完时区的数据之后是存在了前端的 localStorage 里边,时���组件里边也是从 localStorage 拿去默认值来回显。如果当前页面不刷新,那么时间组件就不能更新到最新的 localStorage 数据。

怎么才能让 localStorage 存储的数也变成响应式呢?

实现

  1. 应该写个公共的方法,不仅仅时区数据能用,万一后边其他数据也能用。

  2. 项目是 React 项目,那就写个 hook

  3. 怎么才能让 localStorage 数据变成响应式呢?监听?

失败的案例 1

首先想到的是按照下边这种方式做,

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

得到的测试结果肯定是失败的,但是为啥失败?我们也应该知道一下。查了资料说,使用 localStorage.getItem('timezone') 作为依赖项会导致每次渲染都重新计算依赖项,这不是正确的做法。

具体看一下官方文档:useEffect(setup, dependencies?)

在此说一下第二个参数 dependencies

可选 dependenciessetup 代码中引用的所有响应式值的列表。响应式值包括 props、state 以及所有直接在组件内部声明的变量和函数。如果你的代码检查工具 配置了 React[1],那么它将验证是否每个响应式值都被正确地指定为一个依赖项。依赖项列表的元素数量必须是固定的,并且必须像 [dep1, dep2, dep3] 这样内联编写。React 将使用 `Object.is`[2] 来比较每个依赖项和它先前的值。如果省略此参数,则在每次重新渲染组件之后,将重新运行 Effect 函数。

  • 如果你的一些依赖项是组件内部定义的对象或函数,则存在这样的风险,即它们将 导致 Effect 过多地重新运行。要解决这个问题,请删除不必要的 对象[3] 和 函数[4] 依赖项。你还可以 抽离状态更新[5] 和 非响应式的逻辑[6] 到 Effect 之外。

如果你的 Effect 依赖于在渲染期间创建的对象或函数,则它可能会频繁运行。例如,此 Effect 在每次渲染后重新连接,因为 createOptions 函数 在每次渲染时都不同[7]:

function ChatRoom({ roomId }) {const [message, setMessage] = useState('');function createOptions() { // 🚩 此函数在每次重新渲染都从头开始创建return {serverUrl: serverUrl,roomId: roomId};}useEffect(() => {const options = createOptions(); // 它在 Effect 中被使用const connection = createConnection();connection.connect();return () => connection.disconnect();}, [createOptions]); // 🚩 因此,此依赖项在每次重新渲染都是不同的// ...
}

失败的案例 2

一开始能想到的是监听,那就用 window 上监听事件。

在 React 应用中监听 localStorage 的变化,可以使用 window 对象的 storage 事件。这个事件在同一域名的不同文档之间共享,当某个文档修改 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;

使用方法:

// 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;

经过测试,失败了,没有效果!!!那到底怎么回事呢?哪里出现问题了?查阅资料经过思考,可能出现的问题的原因有:只能监听同源的两个页面之间的 storage 变更,没法监听同一个页面的变更。

成功的案例

import { useState, useEffect } from "react";// 自定义 Hook,用于监听 localStorage 中指定键的变化
function useRefreshLocalStorage(localStorage_key) {// 检查 localStorage_key 是否有效if (!localStorage_key || typeof localStorage_key !== "string") {return [null];}// 创建一个状态变量来保存 localStorage 中的值const [storageValue, setStorageValue] = useState(localStorage.getItem(localStorage_key));useEffect(() => {// 保存原始的 localStorage.setItem 方法const originalSetItem = localStorage.setItem;// 重写 localStorage.setItem 方法,添加事件触发逻辑localStorage.setItem = function(key, newValue) {// 创建一个自定义事件,用于通知 localStorage 的变化const setItemEvent = new CustomEvent("setItemEvent", {detail: { key, newValue },});// 触发自定义事件window.dispatchEvent(setItemEvent);// 调用原始的 localStorage.setItem 方法originalSetItem.apply(this, [key, newValue]);};// 事件处理函数,用于处理自定义事件const handleSetItemEvent = (event) => {const customEvent = event;// 检查事件的键是否是我们关心的 localStorage_keyif (event.detail.key === localStorage_key) {// 更新状态变量 storageValueconst updatedValue = customEvent.detail.newValue;setStorageValue(updatedValue);}};// 添加自定义事件的监听器window.addEventListener("setItemEvent", handleSetItemEvent);// 清除事件监听器和还原原始方法return () => {// 移除自定义事件监听器window.removeEventListener("setItemEvent", handleSetItemEvent);// 还原原始的 localStorage.setItem 方法localStorage.setItem = originalSetItem;};// 依赖数组,只在 localStorage_key 变化时重新运行 useEffect}, [localStorage_key]);// 返回当前的 storageValue// 为啥没有返回 setStorageValue ?// 因为想让用户直接操作自己真实的 “setValue” 方法,这里只做一个只读。return [storageValue];
}export default useRefreshLocalStorage;

具体的实现步骤如上,每一步也加上了注释。

接下来就是测试了,

useTimezone 针对 timezone 数据统一封装,

// 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 ,索性就想着 如何让 localStorage 存储变为响应式 ?

最后给大家推荐个好玩的小程序吧,在短视频时代,去水印小程序成为了用户的热门选择。它能快速、轻松地去除视频中的水印,让你分享更干净的内容。只需上传视频,选择去水印功能,几秒钟后,清晰的画面便呈现在眼前。无论是制作个人视频还是分享精彩瞬间,这款小程序都能帮助你提升视频质量,吸引更多观众。告别水印,让你的创作更加自由,尽情展现你的才华吧!(小程序搜索:去水印AI助手)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1540158.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

SaltStack的state定义主机状态及Jinja模版的使用

在前面我们学习了远程执行模块,这些模块的执行类似语段 she11 脚本,每次执行都会触发一次相同的功能,在大量的 minion 上运行远程命令当然是重要的,但是对于 minion 的环境控制,使用状态进行管理更为合适,转…

从零开始制作AI无人直播插件!

AI无人直播插件应运而生,它利用人工智能技术,实现了直播内容的自动化生成与播放,极大地降低了直播的人力成本和时间成本,本文将带你从零开始,探索如何制作一个AI无人直播插件,并分享五段关键的源代码。 AI…

谷歌深度学习研究揭示OpenAI O1模型优化策略:比规模更重要的计算效率

引言 近年来,大型语言模型(LLMs)如OpenAI的GPT-4和Google DeepMind的Palm 2已成为自然语言处理领域的佼佼者,它们通过生成类人文本、回答复杂问题、编写代码等能力,改变了许多行业的工作方式。然而,随着这…

IO流体系(FiletOutputStream)

书写步骤: 1.创建字节输出流对象 细节1:参数是字符串表示的路径或者是File对象都是可以的 细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的。 细节3:如果文件已经存在,则会清空文件 2.写数据 细节:write方法的参数…

大白话解读末日期权是什么意思?末日期权与黑天鹅!

今天带你了解大白话解读末日期权是什么意思?末日期权与黑天鹅!末日期权与黑天鹅事件的关系主要体现在风险和波动性管理上,交易者需要谨慎对待这两者的互动。 末日期权和期权黑天鹅事件之间的关系主要体现在风险管理和市场波动性上。 末日期…

没有那个文件或目录 #include <bits/libc-header-start.h>

Ubuntu 18.04 编译需要编译32位系统 gcc -ggdb -m32 -c -o exploit.o exploit.c gcc -m32 -L/usr/lib32 exploit.o -o exploit 报错: 解决方法: sudo apt-get install libc6-dev-i386sudo apt-get install gcc-multilib

【C++】哈希表:字母异位词分组(体会泛型编程的强大)

1.题目 2.思路 利用map的特性&#xff0c;第一个值存排好序的string&#xff0c;第二个值存vector<string>。这样就可以很好的将异位词分组。 3.代码 class Solution { public:vector<vector<string>> groupAnagrams(vector<string>& strs) {un…

25届计算机专业毕设选题推荐-基于python的二手电子设备交易平台【源码+文档+讲解】

&#x1f496;&#x1f525;作者主页&#xff1a;毕设木哥 精彩专栏推荐订阅&#xff1a;在 下方专栏&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; 实战项目 文章目录 实战项目 一、基于python的二手电子设备交…

六西格玛绿带培训多少钱?从授“鱼”到授“渔”

六西格玛作为一种全球公认的质量管理方法&#xff0c;其影响力日益扩大&#xff0c;而六西格玛绿带培训作为这一体系中的关键环节&#xff0c;更是吸引了众多希望在职场上脱颖而出的专业人士。本文&#xff0c;深圳天行健企业管理咨询公司将从多个维度深入探讨“六西格玛绿带培…

【大模型】初识大模型(非常详细)零基础入门到精通,收藏这一篇就够了_大模型入门

大模型的定义 大模型是指具有数千万甚至数亿参数的深度学习模型。近年来&#xff0c;随着计算机技术和大数据的快速发展&#xff0c;深度学习在各个领域取得了显著的成果&#xff0c;如自然语言处理&#xff0c;图片生成&#xff0c;工业数字化等。为了提高模型的性能&#xf…

游戏如何应对云手机刷量问题

云手机的实现原理是依托公有云和 ARM 虚拟化技术&#xff0c;为用户在云端提供一个安卓实例&#xff0c;用户可以将手机上的应用上传至云端&#xff0c;再通过视频流的方式&#xff0c;远程实时控制云手机。 市面上常见的几款云手机 原本需要手机提供的计算、存储等能力都改由…

在校三个月备考软考中项顺利拿证,经验分享

作为一名在校生&#xff0c;我在三个月的备考软考中项后成功拿到证书&#xff0c;对于软考中项的考试技巧有着丰富的经验。首先&#xff0c;我给你分享一些备考技巧&#xff1a; 1. 不要死记硬背&#xff01;最好是结合跟班学习和教材双管齐下。先过一遍所有知识点&#xff08…

如何查看Android设备的dpi

adb shell getprop ro.sf.lcd_density adb shell cat /system/build.prop > build_prop.txt shell cat system/build.prop 结果&#xff1a;参考&#xff1a; 如何查看Android设备的dpi_安卓 查看手机dpi-CSDN博客

【里程碑】轻空间SPIKE AIRDOME项目落地印尼雅加达

在经过半年的激烈角逐与严苛考量后&#xff0c;轻空间凭借其卓越的气承式球幕技术&#xff0c;成功赢得印尼最大城市建设商的青睐&#xff0c;正式签约 SPIKE AIRDOME 项目。该项目将落地印尼首都雅加达CBD&#xff0c;成为这一繁华商业中心的全新地标。轻空间技术负责人亲切地…

一些线上常用排查问题的命令

排查CPU过高时使用到的一些命令 top free df top命令 top 命令是一个动态的实时视图&#xff0c;显示系统的整体运行状况&#xff0c;包括 CPU 使用率、内存使用情况、进程信息等。 free 命令 free 命令用于显示系统中物理内存和交换内存的使用情况。 df 命令 df 命令用…

如何从 Nutanix 迁移至 SmartX 超融合?解读 4 类迁移方案和 2 例迁移实践

2022 年底&#xff0c;Nutanix&#xff08;路坦力&#xff09;正式宣布将中国市场交由合作伙伴&#xff08;联想&#xff09;主导销售&#xff0c;并于 2023 年 8 月完成全面转型。转型后&#xff0c;虽然中国用户依旧可以使用 Nutanix 产品&#xff0c;但在软件的续保和维保方…

基于flask+vue框架的传染病防控酒店信息系统zvt93(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;患者,服务人员,病房类型,病房信息,病房分配,需求箱,商品分类,商品信息,购买商品,分配反馈,健康上报,患者信息,患者分配 开题报告内容 基于flaskvue框架的传染病防控酒店信息系统开题报告 一、项目背景 在全球公共卫生事件频发的背景下…

鸿蒙应用生态构建的核心目标

保护开发者和用户利益的同时维护整体系统的安全性&#xff0c;对生态构建者是至关重要的。以开发者为中心&#xff0c;构建端到端应用安全能力&#xff0c;保护应用自身安全、运行时安全&#xff0c;保障开发者权益&#xff0c;是鸿蒙应用生态构建的核心目标。 应用生命周期主要…

汽车焊机数据通信:Profinet转Canopen网关的神奇连接

在汽车制造领域&#xff0c;汽车焊机的高效、稳定运行对于整车质量至关重要。而Profinet转Canopen网关在汽车焊机的数据通信中发挥着关键作用。 Profinet是一种广泛应用于工业自动化领域的通信协议&#xff0c;具有高速、实时、可靠等特点。Canopen则在汽车电子等领域有着广泛…

【Qt笔记】QTabWidget控件详解

目录 引言 一、基本功能 二、核心属性 2.1 标签页管理 2.2 标签位置 2.3 标签形状 2.4 标签可关闭性 2.5 标签可移动性 三、信号与槽 四、高级功能 4.1 动态添加和删除标签页 4.2 自定义标签页的关闭按钮行为 4.3 标签页的上下文菜单 五、样式设置 六、应用示例…