持久性
Jotai 在工具包中有一个用于持久化的 atomWithStorage 函数,支持在 sessionStorage
、localStorage
、AsyncStorage
或 URL hash 中持久化状态。
(注意:这篇指南有些过时,需要一些重写。)
这里还有几种替代实现:
使用 localStorage 的简单模式
const strAtom = atom(localStorage.getItem('myKey') ?? 'foo')const strAtomWithPersistence = atom((get) => get(strAtom),(get, set, newStr) => {set(strAtom, newStr)localStorage.setItem('myKey', newStr)},)
使用 localStorage 和 JSON 解析的辅助函数
const atomWithLocalStorage = (key, initialValue) => {const getInitialValue = () => {const item = localStorage.getItem(key)if (item !== null) {return JSON.parse(item)}return initialValue}const baseAtom = atom(getInitialValue())const derivedAtom = atom((get) => get(baseAtom),(get, set, update) => {const nextValue =typeof update === 'function' ? update(get(baseAtom)) : updateset(baseAtom, nextValue)localStorage.setItem(key, JSON.stringify(nextValue))},)return derivedAtom}
(应添加错误处理。)
使用 AsyncStorage 和 JSON 解析的辅助函数
这需要 onMount。
const atomWithAsyncStorage = (key, initialValue) => {const baseAtom = atom(initialValue)baseAtom.onMount = (setValue) => {;(async () => {const item = await AsyncStorage.getItem(key)setValue(JSON.parse(item))})()}const derivedAtom = atom((get) => get(baseAtom),(get, set, update) => {const nextValue =typeof update === 'function' ? update(get(baseAtom)) : updateset(baseAtom, nextValue)AsyncStorage.setItem(key, JSON.stringify(nextValue))},)return derivedAtom}
不要忘记查看 Async 文档以获取更多关于如何使用异步原子的详细信息。
使用 sessionStorage 的示例
与 AsyncStorage 相同,只需使用 atomWithStorage
工具并用 sessionStorage
覆盖默认存储。
import { atomWithStorage, createJSONStorage } from 'jotai/utils'const storage = createJSONStorage(() => sessionStorage)const someAtom = atomWithStorage('some-key', someInitialValue, storage)
A serialize atom pattern
type Actions =| { type: 'serialize'; callback: (value: string) => void }| { type: 'deserialize'; value: string }const serializeAtom = atom(null, (get, set, action: Actions) => {if (action.type === 'serialize') {const obj = {todos: get(todosAtom).map(get),}action.callback(JSON.stringify(obj))} else if (action.type === 'deserialize') {const obj = JSON.parse(action.value)// 需要错误处理和类型检查set(todosAtom,obj.todos.map((todo: Todo) => atom(todo)),)}})const Persist = () => {const [, dispatch] = useAtom(serializeAtom)const save = () => {dispatch({type: 'serialize',callback: (value) => {localStorage.setItem('serializedTodos', value)},})}const load = () => {const value = localStorage.getItem('serializedTodos')if (value) {dispatch({ type: 'deserialize', value })}}return (<div><button onClick={save}>Save to localStorage</button><button onClick={load}>Load from localStorage</button></div>)}
示例
使用 atomFamily 的模式
type Actions =| { type: 'serialize'; callback: (value: string) => void }| { type: 'deserialize'; value: string }const serializeAtom = atom(null, (get, set, action: Actions) => {if (action.type === 'serialize') {const todos = get(todosAtom)const todoMap: Record<string, { title: string; completed: boolean }> = {}todos.forEach((id) => {todoMap[id] = get(todoAtomFamily({ id }))})const obj = {todos,todoMap,filter: get(filterAtom),}action.callback(JSON.stringify(obj))} else if (action.type === 'deserialize') {const obj = JSON.parse(action.value)// 需要错误处理和类型检查set(filterAtom, obj.filter)obj.todos.forEach((id: string) => {const todo = obj.todoMap[id]set(todoAtomFamily({ id, ...todo }), todo)})set(todosAtom, obj.todos)}})const Persist = () => {const [, dispatch] = useAtom(serializeAtom)const save = () => {dispatch({type: 'serialize',callback: (value) => {localStorage.setItem('serializedTodos', value)},})}const load = () => {const value = localStorage.getItem('serializedTodos')if (value) {dispatch({ type: 'deserialize', value })}}return (<div><button onClick={save}>保存到 localStorage</button><button onClick={load}>从 localStorage 加载</button></div>)}