【React与Vue】如何在页签中监听 LocalStorage 变化?这些方法你都
ztj100 2024-10-27 18:35 201 浏览 0 评论
在开发中,你是否会碰到过这样的需求:需要监听 LocalStorage 的变化。这在不同浏览器页签间是相对简单的,因为浏览器提供了内置的 storage 事件。但在同一个浏览器页签下,却没有直接的方式实现。今天,我们探讨下有几种高效且易用的解决方案,可以帮助轻松应对这种需求!
传统方案的痛点
先来看看浏览器是如何帮助我们处理不同页签的 LocalStorage 变化:
window.addEventListener("storage", (event) => {
if (event.key === "myKey") {
// 执行相应操作
}
});
通过监听 storage 事件,当在其他页签修改 LocalStorage 时,你可以在当前页签捕获到这个变化。但问题是:这种方法只适用于跨页签的 LocalStorage 修改,在同一页签下无法触发该事件。于是,很多开发者开始寻求替代方案,比如:
1、轮询(Polling)
轮询是一种最直观的方式,它定期检查 localStorage 的值是否发生变化。然而,这种方法性能较差,尤其在高频轮询时会对浏览器性能产生较大的影响,因此不适合作为长期方案。
let lastValue = localStorage.getItem('myKey');
setInterval(() => {
const newValue = localStorage.getItem('myKey');
if (newValue !== lastValue) {
lastValue = newValue;
console.log('Detected localStorage change:', newValue);
}
}, 1000); // 每秒检查一次
这种方式实现简单,不依赖复杂机制。但是性能较差,频繁轮询会影响浏览器性能。
2、监听代理(Proxy)或发布-订阅模式
这种方式通过创建一个代理来拦截 localStorage.setItem 的调用。每次数据变更时,我们手动发布一个事件,通知其他监听者。
(function() {
const originalSetItem = localStorage.setItem;
const subscribers = [];
localStorage.setItem = function(key, value) {
originalSetItem.apply(this, arguments);
subscribers.forEach(callback => callback(key, value));
};
function subscribe(callback) {
subscribers.push(callback);
}
subscribe((key, value) => {
if (key === 'myKey') {
console.log('Detected localStorage change:', value);
}
});
localStorage.setItem('myKey', 'newValue');
})();
这种比较灵活,可以用于复杂场景。但是需要手动拦截 setItem,维护成本高(但也是值得推荐的)。
然而,这些方案往往存在性能问题或者开发的复杂度,在高频数据更新的情况下,有一定的性能问题,而且存在一定的风险性。那么有没有可以简单快速,风险性还小的方案呢?
高效的解决方案
既然浏览器不支持同一页签的 storage 事件,我们可以手动触发事件,以此来实现同一页签下的 LocalStorage 变化监听。
1、自定义 Storage 事件
通过手动触发 StorageEvent,你可以在 LocalStorage 更新时同步分发事件,从而实现同一页签下的监听。
localStorage.setItem('myKey', 'value');
// 手动创建并分发 StorageEvent
const storageEvent = new StorageEvent('storage', {
key: 'myKey',
url: window.location.href
});
window.dispatchEvent(storageEvent);
你可以使用相同的监听逻辑来处理数据变化,无论是同一页签还是不同页签:
window.addEventListener("storage", (event) => {
if (event.key === "myKey") {
// 处理 LocalStorage 更新
}
});
这种实现简单、轻量、快捷。但是需要手动触发事件。
2、基于 CustomEvent 的自定义事件
与 StorageEvent 类似,你可以使用 CustomEvent 手动创建并分发事件,实现 localStorage 的同步监听。
localStorage.setItem('myKey', 'newValue');
const customEvent = new CustomEvent('localStorageChange', {
detail: { key: 'myKey', value: 'newValue' }
});
window.dispatchEvent(customEvent);
这种方式适合更加灵活的事件触发场景。CustomEvent不局限于 localStorage 事件,可以扩展到其他功能。
window.addEventListener('localStorageChange', (event) => {
const { key, value } = event.detail;
if (key === 'myKey') {
console.log('Detected localStorage change:', value);
}
});
3、MessageChannel(消息通道)
MessageChannel API 可以在同一个浏览器上下文中发送和接收消息。我们可以通过 MessageChannel 将 localStorage 的变化信息同步到其他部分,起到类似事件监听的效果。
const channel = new MessageChannel();
channel.port1.onmessage = (event) => {
console.log('Detected localStorage change:', event.data);
};
localStorage.setItem('myKey', 'newValue');
channel.port2.postMessage(localStorage.getItem('myKey'));
适合组件通信和复杂应用场景,消息机制较为灵活。相对复杂的实现,可能不适合简单场景。
4、BroadcastChannel
BroadcastChannel 提供了一种更高级的浏览器通信机制,允许多个窗口或页面之间广播消息。你可以通过这个机制将 localStorage 变更同步到多个页面或同一页面的不同部分。
const channel = new BroadcastChannel('storage_channel');
channel.onmessage = (event) => {
console.log('Detected localStorage change:', event.data);
};
localStorage.setItem('myKey', 'newValue');
channel.postMessage({ key: 'myKey', value: 'newValue' });
支持跨页面通信,方便在不同页面间同步数据,易于实现。适用场景较为具体,通常用于复杂的页面通信需求。
这4个方法,主打的就是一个见缝插针,简单快速,风险性低。但是客观角度来讲,每种方案都是有各自优势的。
优势对比
方案 | 优点 | 缺点 | 适用场景 |
轮询 | 实现简单,适合低频监控需求 | 性能差,频繁轮询影响浏览器性能 | 简单场景或临时方案 |
监听代理/发布-订阅模式 | 灵活扩展,适合复杂项目 | 需要手动拦截 setItem,维护成本高 | 需要手动事件发布的场景 |
自定义 StorageEvent | 实现简单,原生支持 storage 事件监听 | 需要手动触发事件 | 同页签下 localStorage 监听 |
自定义事件 | 灵活的事件管理,适合不同场景 | 需要手动触发事件 | 需要自定义触发条件的场景 |
MessageChannel | 适合组件通信和复杂应用场景 | 实现复杂,不适合简单场景 | 高级组件通信需求 |
BroadcastChannel | 跨页面通信,适合复杂通信需求 | 使用场景较具体 | 复杂的多窗口通信 |
如何在 React / Vue 使用
在主流前端框架(如 React 和 Vue)中,监听 LocalStorage 变化并不困难。无论是 React 还是 Vue,你都可以使用自定义的 StorageEvent 或其他方法来实现监听。在此,我们以自定义 StorageEvent 为例,展示如何在 React 和 Vue 中实现 LocalStorage 的监听。
1. 在 React 中使用自定义 StorageEvent
React 是一个基于组件的框架,我们可以使用 React 的生命周期函数(如 useEffect)来监听和处理 LocalStorage 的变化。
import React, { useEffect } from 'react';
const LocalStorageListener = () => {
useEffect(() => {
// 定义 storage 事件监听器
const handleStorageChange = (event) => {
if (event.key === 'myKey') {
console.log('Detected localStorage change:', event.newValue);
}
};
// 添加监听器
window.addEventListener('storage', handleStorageChange);
// 模拟触发自定义的 StorageEvent
const triggerCustomStorageEvent = () => {
const storageEvent = new StorageEvent('storage', {
key: 'myKey',
newValue: 'newValue',
url: window.location.href,
});
window.dispatchEvent(storageEvent);
};
// 组件卸载时移除监听器
return () => {
window.removeEventListener('storage', handleStorageChange);
};
}, []); // 空依赖数组表示该 effect 只会在组件挂载时运行
return (
<div>
<button onClick={() => localStorage.setItem('myKey', 'newValue')}>
修改 localStorage
</button>
<button onClick={() => window.dispatchEvent(new StorageEvent('storage', {
key: 'myKey',
newValue: localStorage.getItem('myKey'),
url: window.location.href,
}))}>
手动触发 StorageEvent
</button>
</div>
);
};
export default LocalStorageListener;
- useEffect 是 React 的一个 Hook,用来处理副作用,在这里我们用它来注册和清除事件监听器。
- 我们手动触发了 StorageEvent,以便在同一页面中监听 LocalStorage 的变化。
2. 在 Vue 中使用自定义 StorageEvent
在 Vue 3 中,我们可以使用 onMounted 和 onUnmounted 这两个生命周期钩子来管理事件监听器。(Vue 3 Composition API):
<template>
<div>
<button @click="updateLocalStorage">修改 localStorage</button>
<button @click="triggerCustomStorageEvent">手动触发 StorageEvent</button>
</div>
</template>
<script lang="ts" setup>
import { onMounted, onUnmounted } from 'vue';
const handleStorageChange = (event: StorageEvent) => {
if (event.key === 'myKey') {
console.log('Detected localStorage change:', event.newValue);
}
};
const updateLocalStorage = () => {
localStorage.setItem('myKey', 'newValue');
};
const triggerCustomStorageEvent = () => {
const storageEvent = new StorageEvent('storage', {
key: 'myKey',
newValue: 'newValue',
url: window.location.href,
});
window.dispatchEvent(storageEvent);
};
onMounted(() => {
window.addEventListener('storage', handleStorageChange);
});
onUnmounted(() => {
window.removeEventListener('storage', handleStorageChange);
});
</script>
- 使用了 Vue 的 Composition API,其中 onMounted 和 onUnmounted 类似于 React 的 useEffect,用于在组件挂载和卸载时管理副作用。
- 同样手动触发了 StorageEvent 来监听同一页面中的 LocalStorage 变化。
提炼封装一下
无论是 React 还是 Vue,将自定义 StorageEvent 实现为一个组件或工具函数是常见的做法。你可以将上面的逻辑提取到一个独立的 hook 或工具函数中,方便在项目中多次使用。
在 React 中提取为 Hook
import { useEffect } from 'react';
const useLocalStorageListener = (key, callback) => {
useEffect(() => {
const handleStorageChange = (event) => {
if (event.key === key) {
callback(event.newValue);
}
};
window.addEventListener('storage', handleStorageChange);
return () => {
window.removeEventListener('storage', handleStorageChange);
};
}, [key, callback]);
};
export default useLocalStorageListener;
在 Vue 中提取为工具函数
import { onMounted, onUnmounted } from 'vue';
export const useLocalStorageListener = (key: string, callback: (value: string | null) => void) => {
const handleStorageChange = (event: StorageEvent) => {
if (event.key === key) {
callback(event.newValue);
}
};
onMounted(() => {
window.addEventListener('storage', handleStorageChange);
});
onUnmounted(() => {
window.removeEventListener('storage', handleStorageChange);
});
};
- 在 React 中,我们创建了一个自定义 Hook useLocalStorageListener,通过传入监听的 key 和回调函数来捕获 LocalStorage 的变化。
- 在 Vue 中,我们创建了一个工具函数 useLocalStorageListener,同样通过传入 key 和回调函数来监听变化。
总结
在同一个浏览器页签中监听 localStorage 的变化并非难事,但不同场景下需要不同的方案。从简单的轮询到高级的 BroadcastChannel,本文介绍的几种方案各有优缺点。根据你的实际需求,选择合适的方案可以帮助你更高效地解决问题。
- 简单需求:可以考虑使用自定义 StorageEvent 或 CustomEvent 实现监听。
- 复杂需求:对于更高级的场景,如跨页面通信,MessageChannel 或 BroadcastChannel 是更好的选择。
如果你有其他的优化技巧或问题,欢迎在评论区分享,让我们一起交流更多的解决方案!
相关推荐
- 如何将数据仓库迁移到阿里云 AnalyticDB for PostgreSQL
-
阿里云AnalyticDBforPostgreSQL(以下简称ADBPG,即原HybridDBforPostgreSQL)为基于PostgreSQL内核的MPP架构的实时数据仓库服务,可以...
- Python数据分析:探索性分析
-
写在前面如果你忘记了前面的文章,可以看看加深印象:Python数据处理...
- C++基础语法梳理:算法丨十大排序算法(二)
-
本期是C++基础语法分享的第十六节,今天给大家来梳理一下十大排序算法后五个!归并排序...
- C 语言的标准库有哪些
-
C语言的标准库并不是一个单一的实体,而是由一系列头文件(headerfiles)组成的集合。每个头文件声明了一组相关的函数、宏、类型和常量。程序员通过在代码中使用#include<...
- [深度学习] ncnn安装和调用基础教程
-
1介绍ncnn是腾讯开发的一个为手机端极致优化的高性能神经网络前向计算框架,无第三方依赖,跨平台,但是通常都需要protobuf和opencv。ncnn目前已在腾讯多款应用中使用,如QQ,Qzon...
- 用rust实现经典的冒泡排序和快速排序
-
1.假设待排序数组如下letmutarr=[5,3,8,4,2,7,1];...
- ncnn+PPYOLOv2首次结合!全网最详细代码解读来了
-
编辑:好困LRS【新智元导读】今天给大家安利一个宝藏仓库miemiedetection,该仓库集合了PPYOLO、PPYOLOv2、PPYOLOE三个算法pytorch实现三合一,其中的PPYOL...
- C++特性使用建议
-
1.引用参数使用引用替代指针且所有不变的引用参数必须加上const。在C语言中,如果函数需要修改变量的值,参数必须为指针,如...
- Qt4/5升级到Qt6吐血经验总结V202308
-
00:直观总结增加了很多轮子,同时原有模块拆分的也更细致,估计为了方便拓展个管理。把一些过度封装的东西移除了(比如同样的功能有多个函数),保证了只有一个函数执行该功能。把一些Qt5中兼容Qt4的方法废...
- 到底什么是C++11新特性,请看下文
-
C++11是一个比较大的更新,引入了很多新特性,以下是对这些特性的详细解释,帮助您快速理解C++11的内容1.自动类型推导(auto和decltype)...
- 掌握C++11这些特性,代码简洁性、安全性和性能轻松跃升!
-
C++11(又称C++0x)是C++编程语言的一次重大更新,引入了许多新特性,显著提升了代码简洁性、安全性和性能。以下是主要特性的分类介绍及示例:一、核心语言特性1.自动类型推导(auto)编译器自...
- 经典算法——凸包算法
-
凸包算法(ConvexHull)一、概念与问题描述凸包是指在平面上给定一组点,找到包含这些点的最小面积或最小周长的凸多边形。这个多边形没有任何内凹部分,即从一个多边形内的任意一点画一条线到多边形边界...
- 一起学习c++11——c++11中的新增的容器
-
c++11新增的容器1:array当时的初衷是希望提供一个在栈上分配的,定长数组,而且可以使用stl中的模板算法。array的用法如下:#include<string>#includ...
- C++ 编程中的一些最佳实践
-
1.遵循代码简洁原则尽量避免冗余代码,通过模块化设计、清晰的命名和良好的结构,让代码更易于阅读和维护...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- node卸载 (33)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- exceptionininitializererror (33)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)