当页面呈现时,挂钩正在检查存储中是否存在模拟信息,如果存在,则在全局AppState上下文中设置这些信息。
const impersonateStorageKey = `impersonation_${config.environment}`
// signature const impersonate: (empScope: number) => void
const { currentImpersonation, impersonate } = useAppContext()
useEffect(() => {
if (!window || !window.localStorage) return;
const storageString = localStorage.getItem(impersonateStorageKey)
if (!storageString) return;
const data = JSON.parse(storageString)
impersonate(data.currentImpersonation)
}, [impersonateStorageKey])
使用第二个钩子,将当前模拟身份的更改持久化到存储中:
useEffect(() => {
if (!window || !window.localStorage) return;
localStorage.setItem(impersonateStorageKey, JSON.stringify({ /* ... */}))
}, [currentImpersonation, impersonateStorageKey])
加上useAppContext
的相关位
const useAppContext = () => {
const { state, dispatch } = useContext(AppContext)
if (!state) {
throw new Error("useAppContext must be used within within AppContextProvider")
}
const impersonate = (employeeScope: string | number) => dispatch({ type: 'IMPERSONATE', value: employeeScope })
const currentImpersonation = state.currentImpersonation
return {
impersonate,
currentImpersonation,
}
}
这是正常的,但linter抱怨说,第一个useEffect钩子中缺少依赖模拟
当我将impersonate
添加到依赖数组时,这将导致一个持续的更新循环,并使应用程序没有响应。
我知道是什么导致了这种行为,但我没有找到一个解决方案(除了忽略规则(来解决如何打破循环和让linter高兴。
我可以采取什么方法?
使用useCallback
:创建函数时,可以对其进行记忆
const useAppContext = () => {
const { state, dispatch } = useContext(AppContext)
const impersonate = useCallback(
(employeeScope: string | number) => dispatch({
type: 'IMPERSONATE',
value: employeeScope
}), [dispatch])
if (!state) {
throw new Error("useAppContext must be used within within AppContextProvider")
}
const currentImpersonation = state.currentImpersonation
return {
impersonate,
currentImpersonation,
}
}
如果不能,解决方法是将函数放在引用中。ref
是对对象的不可变引用,具有可变的current
属性。由于ref
本身是不可变的,您可以将其用作依赖项,而无需激活useEffect
(linter知道它,您甚至不需要将其声明为依赖项(。你可以随心所欲地变异current
。
const impersonateRef = useRef(impersonate)
useEffect(() => {
impersonateRef.current = impersonate
}, [impersonate])
useEffect(() => {
if (!window || !window.localStorage) return
const storageString = localStorage.getItem(impersonateStorageKey)
if (!storageString) return
const data = JSON.parse(storageString)
impersonateRef.current(data.currentImpersonation)
}, [impersonateStorageKey])