如何让自定义Hook useGetFooId可在Redux Provider外部安全调用?
问题:让Redux Hook在Provider外部安全调用
我有一个名为useGetFooId的Hook,用于从Redux store中获取Foo ID,并包含降级逻辑:
- 若Redux store中已设置Foo ID,则返回该ID(部分场景下store中无此ID);
- 若无法从Redux store获取,则尝试从其他可靠性较低的来源获取。
其代码大致如下:
const useGetFooId = () => { const { fooId: fooIdFromSelector } = useSelector(uiSelector); const fooIdFromLessReliablePlace = getFooIdFromLessReliablePlace(); const fooIdFromVeryUnreliablePlace = getVeryUnreliableFooId(); return fooIdFromSelector ?? fooIdFromLessReliablePlace ?? fooIdFromVeryUnreliablePlace ?? null; }
现在我希望让useGetFooId可以在Redux Provider外部安全调用(该Foo ID与应用根节点的错误边界组件展示逻辑相关)。当前在Provider外部调用时会报错:Cannot read properties of null (reading 'store')。
期望行为:若在Provider外部调用useGetFooId,应使用与store中fooId未定义时相同的降级逻辑,即返回fooIdFromLessReliablePlace ?? fooIdFromVeryUnreliablePlace ?? null。
是否有官方支持的方法,可仅在Provider可用时才访问Redux store?我原本考虑用try/catch,但这似乎违反了Hooks规则。
解决方案
Redux官方有支持的方法,不用try/catch也不违反Hooks规则,核心是通过检查Redux上下文是否存在来判断当前是否在Provider内部:
- 先导入
ReactReduxContext(Redux内部用的上下文)和React的useContext钩子 - 用
useContext拿到Redux上下文实例,就能知道有没有Provider了 - 要是上下文存在,就从store里取状态;没有的话直接走降级逻辑就行
改好的代码是这样的:
import { useContext } from 'react'; import { ReactReduxContext } from 'react-redux'; const useGetFooId = () => { const reduxContext = useContext(ReactReduxContext); let fooIdFromSelector = undefined; // 只有在Provider存在的时候才读store if (reduxContext) { const store = reduxContext.store; const uiState = uiSelector(store.getState()); fooIdFromSelector = uiState.fooId; } const fooIdFromLessReliablePlace = getFooIdFromLessReliablePlace(); const fooIdFromVeryUnreliablePlace = getVeryUnreliableFooId(); return fooIdFromSelector ?? fooIdFromLessReliablePlace ?? fooIdFromVeryUnreliablePlace ?? null; }
说明:
ReactReduxContext是Redux官方暴露的内部上下文,用来判断是否在Provider范围内完全靠谱- 这里没条件调用
useSelector(毕竟Hooks要求必须顶层调用),而是直接用store.getState()拿状态,效果和useSelector同步读取是一样的 - 所有Hooks都是在组件顶层无条件调用的,完全符合规则
内容的提问来源于stack exchange,提问作者Alex von Brandenfels
相关产品推荐
相关产品推荐

