温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

业务层hooks怎么封装useSessionStorage

发布时间:2022-08-26 10:32:31 来源:亿速云 阅读:136 作者:iii 栏目:开发技术

业务层hooks怎么封装useSessionStorage

在现代前端开发中,React Hooks 已经成为了一种非常流行的状态管理方式。Hooks 提供了一种更简洁、更灵活的方式来管理组件的状态和副作用。其中,useStateuseEffect 是最常用的 Hooks 之一。然而,在实际开发中,我们经常需要将状态持久化到浏览器的 sessionStorage 中,以便在页面刷新或重新加载时能够恢复之前的状态。本文将详细介绍如何在业务层封装一个 useSessionStorage Hook,以便在项目中更方便地使用 sessionStorage

1. 什么是 sessionStorage

sessionStorage 是浏览器提供的一种本地存储机制,它允许我们在浏览器会话期间存储数据。与 localStorage 不同,sessionStorage 中的数据只在当前会话期间有效,当用户关闭浏览器标签页或窗口时,数据将被清除。

sessionStorage 的主要特点包括:

  • 会话级别存储:数据只在当前浏览器会话期间有效。
  • 键值对存储:数据以键值对的形式存储,键和值都必须是字符串。
  • 同源策略sessionStorage 受同源策略限制,不同源的数据无法共享。

2. 为什么需要封装 useSessionStorage

在实际开发中,我们经常需要将组件的状态持久化到 sessionStorage 中。例如,用户在表单中输入的数据、用户的偏好设置等。如果每次都需要手动操作 sessionStorage,代码会变得冗长且难以维护。因此,封装一个 useSessionStorage Hook 可以让我们更方便地管理 sessionStorage 中的数据。

封装 useSessionStorage 的好处包括:

  • 简化代码:通过封装,我们可以将 sessionStorage 的操作抽象成一个 Hook,减少重复代码。
  • 提高可维护性:将 sessionStorage 的逻辑集中在一个地方,便于维护和修改。
  • 增强可读性:使用 Hook 的方式可以让代码更加直观和易读。

3. 如何封装 useSessionStorage

接下来,我们将详细介绍如何封装一个 useSessionStorage Hook。我们将从基本的实现开始,逐步增加功能,最终实现一个功能完善的 useSessionStorage Hook。

3.1 基本实现

首先,我们来实现一个最基本的 useSessionStorage Hook。这个 Hook 将允许我们存储和读取 sessionStorage 中的数据。

import { useState, useEffect } from 'react'; function useSessionStorage(key, initialValue) { const [storedValue, setStoredValue] = useState(() => { try { const item = window.sessionStorage.getItem(key); return item ? JSON.parse(item) : initialValue; } catch (error) { console.error(error); return initialValue; } }); const setValue = (value) => { try { const valueToStore = value instanceof Function ? value(storedValue) : value; setStoredValue(valueToStore); window.sessionStorage.setItem(key, JSON.stringify(valueToStore)); } catch (error) { console.error(error); } }; return [storedValue, setValue]; } export default useSessionStorage; 

3.1.1 代码解析

  • useState:我们使用 useState 来管理 sessionStorage 中的数据。初始值通过 window.sessionStorage.getItem(key) 获取,如果 sessionStorage 中没有对应的值,则使用 initialValue

  • setValue:这是一个更新 sessionStorage 数据的函数。它接受一个值或一个函数作为参数。如果传入的是一个函数,那么这个函数将接收当前的值作为参数,并返回一个新的值。然后,我们将这个新值存储到 sessionStorage 中。

  • JSON.parseJSON.stringify:由于 sessionStorage 只能存储字符串,我们需要使用 JSON.stringify 将对象转换为字符串,使用 JSON.parse 将字符串转换回对象。

3.1.2 使用示例

import React from 'react'; import useSessionStorage from './useSessionStorage'; function App() { const [name, setName] = useSessionStorage('name', 'John Doe'); return ( <div> <h1>Hello, {name}!</h1> <input type="text" value={name} onChange={(e) => setName(e.target.value)} /> </div> ); } export default App; 

在这个示例中,我们使用 useSessionStorage 来存储用户的名字。当用户在输入框中输入名字时,名字会被存储到 sessionStorage 中。即使页面刷新,名字也会被保留。

3.2 处理复杂数据类型

在上面的实现中,我们假设 sessionStorage 中存储的是简单的数据类型(如字符串、数字、布尔值等)。然而,在实际开发中,我们可能需要存储更复杂的数据类型,如数组、对象等。为了处理这些复杂数据类型,我们需要对 useSessionStorage 进行一些改进。

3.2.1 改进代码

import { useState, useEffect } from 'react'; function useSessionStorage(key, initialValue) { const [storedValue, setStoredValue] = useState(() => { try { const item = window.sessionStorage.getItem(key); return item ? JSON.parse(item) : initialValue; } catch (error) { console.error(error); return initialValue; } }); const setValue = (value) => { try { const valueToStore = value instanceof Function ? value(storedValue) : value; setStoredValue(valueToStore); window.sessionStorage.setItem(key, JSON.stringify(valueToStore)); } catch (error) { console.error(error); } }; useEffect(() => { const handleStorageChange = (event) => { if (event.key === key) { setStoredValue(JSON.parse(event.newValue)); } }; window.addEventListener('storage', handleStorageChange); return () => { window.removeEventListener('storage', handleStorageChange); }; }, [key]); return [storedValue, setValue]; } export default useSessionStorage; 

3.2.2 代码解析

  • useEffect:我们使用 useEffect 来监听 sessionStorage 的变化。当 sessionStorage 中的数据发生变化时,我们会更新组件的状态。这样可以确保当其他标签页或窗口修改了 sessionStorage 中的数据时,当前页面也能及时更新。

  • handleStorageChange:这是一个事件处理函数,当 sessionStorage 发生变化时,它会检查变化的键是否与当前 Hook 使用的键一致。如果一致,则更新组件的状态。

3.2.3 使用示例

import React from 'react'; import useSessionStorage from './useSessionStorage'; function App() { const [todos, setTodos] = useSessionStorage('todos', []); const addTodo = () => { const newTodo = { id: Date.now(), text: 'New Todo' }; setTodos([...todos, newTodo]); }; return ( <div> <h1>Todos</h1> <ul> {todos.map((todo) => ( <li key={todo.id}>{todo.text}</li> ))} </ul> <button onClick={addTodo}>Add Todo</button> </div> ); } export default App; 

在这个示例中,我们使用 useSessionStorage 来存储一个待办事项列表。当用户点击“Add Todo”按钮时,一个新的待办事项会被添加到列表中,并存储到 sessionStorage 中。

3.3 处理过期时间

在某些情况下,我们可能希望 sessionStorage 中的数据在一定时间后自动过期。例如,用户的登录状态可能只需要在一段时间内有效。为了实现这个功能,我们可以对 useSessionStorage 进行进一步的改进。

3.3.1 改进代码

import { useState, useEffect } from 'react'; function useSessionStorage(key, initialValue, expirationMinutes) { const [storedValue, setStoredValue] = useState(() => { try { const item = window.sessionStorage.getItem(key); if (item) { const { value, timestamp } = JSON.parse(item); const isExpired = Date.now() - timestamp > expirationMinutes * 60 * 1000; return isExpired ? initialValue : value; } return initialValue; } catch (error) { console.error(error); return initialValue; } }); const setValue = (value) => { try { const valueToStore = value instanceof Function ? value(storedValue) : value; setStoredValue(valueToStore); const item = { value: valueToStore, timestamp: Date.now(), }; window.sessionStorage.setItem(key, JSON.stringify(item)); } catch (error) { console.error(error); } }; useEffect(() => { const handleStorageChange = (event) => { if (event.key === key) { const { value, timestamp } = JSON.parse(event.newValue); const isExpired = Date.now() - timestamp > expirationMinutes * 60 * 1000; setStoredValue(isExpired ? initialValue : value); } }; window.addEventListener('storage', handleStorageChange); return () => { window.removeEventListener('storage', handleStorageChange); }; }, [key, expirationMinutes, initialValue]); return [storedValue, setValue]; } export default useSessionStorage; 

3.3.2 代码解析

  • expirationMinutes:我们新增了一个 expirationMinutes 参数,用于指定数据的过期时间(以分钟为单位)。

  • timestamp:在存储数据时,我们不仅存储数据的值,还存储当前的时间戳。这样,在读取数据时,我们可以检查数据是否已经过期。

  • isExpired:在读取数据时,我们检查当前时间与存储时间戳的差值是否超过了过期时间。如果超过了,则返回初始值,否则返回存储的值。

3.3.3 使用示例

import React from 'react'; import useSessionStorage from './useSessionStorage'; function App() { const [token, setToken] = useSessionStorage('token', null, 5); // 5分钟后过期 const login = () => { setToken('fake-token'); }; const logout = () => { setToken(null); }; return ( <div> <h1>Token: {token || 'No Token'}</h1> <button onClick={login}>Login</button> <button onClick={logout}>Logout</button> </div> ); } export default App; 

在这个示例中,我们使用 useSessionStorage 来存储用户的登录令牌。令牌在5分钟后会自动过期。当用户点击“Login”按钮时,令牌会被存储到 sessionStorage 中;当用户点击“Logout”按钮时,令牌会被清除。

3.4 处理同步更新

在某些情况下,我们可能希望在多个组件之间共享 sessionStorage 中的数据,并且当一个组件更新数据时,其他组件也能及时响应。为了实现这个功能,我们可以使用 useEffect 来监听 sessionStorage 的变化,并在数据变化时更新组件的状态。

3.4.1 改进代码

import { useState, useEffect } from 'react'; function useSessionStorage(key, initialValue, expirationMinutes) { const [storedValue, setStoredValue] = useState(() => { try { const item = window.sessionStorage.getItem(key); if (item) { const { value, timestamp } = JSON.parse(item); const isExpired = Date.now() - timestamp > expirationMinutes * 60 * 1000; return isExpired ? initialValue : value; } return initialValue; } catch (error) { console.error(error); return initialValue; } }); const setValue = (value) => { try { const valueToStore = value instanceof Function ? value(storedValue) : value; setStoredValue(valueToStore); const item = { value: valueToStore, timestamp: Date.now(), }; window.sessionStorage.setItem(key, JSON.stringify(item)); window.dispatchEvent(new Event('storage')); } catch (error) { console.error(error); } }; useEffect(() => { const handleStorageChange = (event) => { if (event.key === key) { const { value, timestamp } = JSON.parse(event.newValue); const isExpired = Date.now() - timestamp > expirationMinutes * 60 * 1000; setStoredValue(isExpired ? initialValue : value); } }; window.addEventListener('storage', handleStorageChange); return () => { window.removeEventListener('storage', handleStorageChange); }; }, [key, expirationMinutes, initialValue]); return [storedValue, setValue]; } export default useSessionStorage; 

3.4.2 代码解析

  • window.dispatchEvent:在 setValue 函数中,我们使用 window.dispatchEvent 手动触发一个 storage 事件。这样,其他组件也能监听到 sessionStorage 的变化,并及时更新状态。

3.4.3 使用示例

import React from 'react'; import useSessionStorage from './useSessionStorage'; function ComponentA() { const [count, setCount] = useSessionStorage('count', 0); return ( <div> <h1>Component A: {count}</h1> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); } function ComponentB() { const [count, setCount] = useSessionStorage('count', 0); return ( <div> <h1>Component B: {count}</h1> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); } function App() { return ( <div> <ComponentA /> <ComponentB /> </div> ); } export default App; 

在这个示例中,我们有两个组件 ComponentAComponentB,它们共享同一个 sessionStoragecount。当其中一个组件更新 count 时,另一个组件也会自动更新。

3.5 处理错误和边界情况

在实际开发中,我们可能会遇到一些错误和边界情况,例如 sessionStorage 不可用、存储空间不足等。为了确保 useSessionStorage 的健壮性,我们需要对这些情况进行处理。

3.5.1 改进代码

import { useState, useEffect } from 'react'; function useSessionStorage(key, initialValue, expirationMinutes) { const [storedValue, setStoredValue] = useState(() => { try { if (typeof window === 'undefined') { return initialValue; } const item = window.sessionStorage.getItem(key); if (item) { const { value, timestamp } = JSON.parse(item); const isExpired = Date.now() - timestamp > expirationMinutes * 60 * 1000; return isExpired ? initialValue : value; } return initialValue; } catch (error) { console.error(error); return initialValue; } }); const setValue = (value) => { try { if (typeof window === 'undefined') { console.warn('sessionStorage is not available'); return; } const valueToStore = value instanceof Function ? value(storedValue) : value; setStoredValue(valueToStore); const item = { value: valueToStore, timestamp: Date.now(), }; window.sessionStorage.setItem(key, JSON.stringify(item)); window.dispatchEvent(new Event('storage')); } catch (error) { console.error(error); } }; useEffect(() => { if (typeof window === 'undefined') { return; } const handleStorageChange = (event) => { if (event.key === key) { const { value, timestamp } = JSON.parse(event.newValue); const isExpired = Date.now() - timestamp > expirationMinutes * 60 * 1000; setStoredValue(isExpired ? initialValue : value); } }; window.addEventListener('storage', handleStorageChange); return () => { window.removeEventListener('storage', handleStorageChange); }; }, [key, expirationMinutes, initialValue]); return [storedValue, setValue]; } export default useSessionStorage; 

3.5.2 代码解析

  • typeof window === 'undefined':我们检查 window 对象是否存在,以确保代码在服务器端渲染(SSR)时不会报错。如果 window 对象不存在,则直接返回初始值。

  • console.warn:在 setValue 函数中,如果 sessionStorage 不可用,我们会输出一个警告信息。

3.5.3 使用示例

import React from 'react'; import useSessionStorage from './useSessionStorage'; function App() { const [theme, setTheme] = useSessionStorage('theme', 'light'); return ( <div> <h1>Theme: {theme}</h1> <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}> Toggle Theme </button> </div> ); } export default App; 

在这个示例中,我们使用 useSessionStorage 来存储用户选择的主题。如果 sessionStorage 不可用,代码仍然可以正常运行,并且不会报错。

4. 总结

通过本文的介绍,我们详细讲解了如何在业务层封装一个 useSessionStorage Hook。我们从基本的实现开始,逐步增加了处理复杂数据类型、过期时间、同步更新以及错误处理等功能。最终,我们实现了一个功能完善、健壮的 useSessionStorage Hook,可以在实际项目中方便地使用。

封装 useSessionStorage 不仅简化了代码,还提高了代码的可维护性和可读性。希望本文对你理解和应用 React Hooks 有所帮助。在实际开发中,你可以根据具体需求对 useSessionStorage 进行进一步的定制和扩展。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI