atomWithStorage
引用: https://github.com/pmndrs/jotai/pull/394
import { useAtom } from "jotai";import { atomWithStorage } from "jotai/utils";const darkModeAtom = atomWithStorage("darkMode", false);const Page = () => {const [darkMode, setDarkMode] = useAtom(darkModeAtom);return (<><h1>Welcome to {darkMode ? "dark" : "light"} mode!</h1><button onClick={() => setDarkMode(!darkMode)}>toggle theme</button></>);};
atomWithStorage
函数创建一个原子,其值保存在用于 React 的 localStorage
或 sessionStorage
或用于 React Native 的 AsyncStorage
中。
参数
key (required): 与 localStorage、sessionStorage 或 AsyncStorage 同步状态时用作 key 的唯一字符串
initialValue (required): 原子初始值
storage (optional): 一个对象:
- 用于存储/检索持久状态的
getItem
和setItem
方法; 默认使用localStorage
进行存储/检索,使用JSON.stringify()
/JSON.parse()
进行序列化/反序列化。 - 可选地,存储有一个
subscribe
属性,可用于同步存储。 默认的localStorage
处理跨表同步的storage
事件。 - 可选地,存储有一个
delayInit
(boolean
) 属性,可以用来告诉 jotai 是否使用 SuspensedelayInit: true
不会在第一次读取原子值时暂停delayInit: false
(默认)将在第一次读取原子值时暂停
服务器端渲染
任何依赖于存储原子值的 JSX 标记(例如,className
或 style
属性)在服务器上呈现时将使用 initialValue
(因为 localStorage
和 sessionStorage
在服务器上不可用)。
这意味着如果用户的 storedValue
与 initialValue
不同,那么最初作为 HTML 提供给用户浏览器的内容与 React 在 rehydration 过程中所期望的内容之间将存在不匹配。
针对此问题的建议解决方法是通过将内容包装在 [自定义<ClientOnly>
包装器](https://www.joshwcomeau.com/react/the-perils-of-rehydration/#abstractions),仅在 rehydration 后呈现。 替代解决方案在技术上是可行的,但在将 initialValue
交换为 storedValue
时需要短暂的“闪烁”,这可能会导致不愉快的用户体验,因此建议采用此解决方案。
从存储中删除项目
对于要从存储中删除项目的情况,
使用 atomWithStorage
创建的原子在写入时接受 RESET
符号。
有关用法,请参见以下示例:
import { useAtom } from "jotai";import { atomWithStorage, RESET } from "jotai/utils";const textAtom = atomWithStorage("text", "hello");const TextBox = () => {const [text, setText] = useAtom(textAtom);return (<><input value={text} onChange={(e) => setText(e.target.value)} /><button onClick={() => setText(RESET)}>Reset (to 'hello')</button></>);};
如果需要,您还可以根据先前的值进行条件重置。
如果您希望在先前的值满足条件的情况下清除 localStorage 中的键,这将特别有用。
下面举例说明了这种用法,只要前一个值为 true
,就会清除 visible
键。
import { useAtom } from 'jotai'import { atomWithStorage, RESET } from 'jotai/utils'const isVisibleAtom = atomWithStorage('visible', false)const TextBox = () => {const [isVisible, setIsVisible] = useAtom(isVisibleAtom)return (<>{ isVisible && <h1>Header is visible!</h1> }<button onClick={() => setIsVisible((prev) => prev ? RESET : true))}>Toggle visible</button></>)}
React-Native 实现
您可以使用任何实现 getItem
、setItem
和 removeItem
的库。
假设您将使用社区提供的标准 AsyncStorage。
import { atomWithStorage, createJSONStorage } from "jotai/utils";import AsyncStorage from "@react-native-async-storage/async-storage";const storage = createJSONStorage(() => AsyncStorage);const content = {}; // 任何可序列化的 JSONconst storedAtom = atomWithStorage("stored-key", content, storage);