我正在使用useReducer钩子来保存一些全局状态。因为我想在浏览器关闭时保存一些设置,所以我将这些设置保存到本地存储中。
目前,我使用分派保存设置,并使用一个单独的函数将其保存到本地存储,但如果设置在分派后自动保存就更好了。(有时我忘记保存到本地存储,并且状态/本地存储之间存在差异)
从本地存储中读取状态不是问题。为此,我在useReducer钩子中使用了initialState参数。
我认为答案是不这样做,但有什么替代方案呢?(不使用redux)
发布于 2019-01-24 20:45:15
我认为让一个服务负责在localStorage中存储数据是明智的。因此,您可能希望创建一个具有get和set函数的服务。您可以在redux中从effect调用服务。
在我看来,减速器是用来改变状态的。
您还可以使用rxjs等待reducer更新您的状态,然后获取它并使用您的服务将其保存到localStorage。
顺便说一句,依赖于你的需求,我真的看不出你为什么不应该在localStorage中存储数据,只要你记住你的redux状态是你唯一的事实。在我看来,将数据存储在某个地方以在初始化时恢复该状态是一个很好的方法。
下面是一个使用ngrx的示例:
@Effect()
myAction$: Observable<Action> = this.actions$.pipe(
ofType<MyAction>(actions.myAction),
debounceTime(300),
switchMap((action) =>
this.service.post(action.dto).pipe(
map((response: SomeDto) => {
// This updates the state using a reducer
return new CreateShortenedLinkSuccess(response);
}),
tap((value) => {
// Here, you can use the value param, to save
// changes to localStorage
this.router.navigate([`/mgmt/link/${value.dto.id}`]);
}),
catchError((response: HttpErrorResponse) => {
// Do scary stuff
})
)
)
);
发布于 2020-01-16 20:30:50
我发现@Zaid Crouch是一个很棒的工具,但它不能处理来自不同窗口(tab/iframe/popup)的本地存储更新。
import { useReducer, useEffect, Dispatch } from 'react'
// Credits: https://stackoverflow.com/questions/54346866/save-to-localstorage-from-reducer-hook
export type ReducerType<T> = (state: T, action: ActionType) => (T)
export type InitType<T> = (state: T) => void
export interface ActionType {
type: string
}
var dispatcher:Dispatch<ActionType> | null = null
const LOCAL_STORAGE_UPDATED_IN_A_DIFFERENT_WINDOW = "LOCAL_STORAGE_UPDATED_IN_A_DIFFERENT_WINDOW"
export function useLocallyPersistedReducer<T>
(reducer: ReducerType<T>, defaultState: T, storageKey: string, init?:InitType<T>) : [T, Dispatch<ActionType>] {
const reducerWrapper = (status: T, action: ActionType) => {
switch (action.type){
case LOCAL_STORAGE_UPDATED_IN_A_DIFFERENT_WINDOW:
const statusReadFromLocalStorage = JSON.parse(localStorage.getItem(storageKey) || "{}")
return statusReadFromLocalStorage
default: return reducer(status, action)
}
}
const [state, dispatch] = useReducer(reducerWrapper, defaultState, (defaultState) => {
const persisted = JSON.parse(localStorage.getItem(storageKey) as string)
return persisted !== null
? persisted
: init ? init(defaultState) : defaultState
})
// NOTE Even if this codes runs multiple time we add only one event listener as long as the callback is singleton
dispatcher = dispatch
window.addEventListener('storage', listenForStorageChangesInOtherWindows, {once: true});
useEffect(() => {
localStorage.setItem(storageKey, JSON.stringify(state))
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [localStorage, storageKey, state])
return [state, dispatch]
}
const listenForStorageChangesInOtherWindows = (key: any) => {
dispatcher && dispatcher({type: LOCAL_STORAGE_UPDATED_IN_A_DIFFERENT_WINDOW})
}
https://stackoverflow.com/questions/54346866
复制相似问题