reactjs - React useReducer 和 context:如何提供状态选择器?
问题描述
在最初的问题中我从来没有明确表示过,但我试图在没有Redux 的情况下完成所有这些,这意味着没有 useSelector();
这是一个使用原生 React 来实现选择器的练习。
我正在尝试使用钩子构建类似 Redux 的安排,并且我从这个人那里大量借用
所以,我们有一个商店:
const CarStore = ({ children }) => {
const [state, dispatch] = useReducer(
carReducer,
[
{
type: 'fast',
mpg: 'bad',
},
],
);
return (
<CarStateContext.Provider value={selectors}>
<CarDispatchContext.Provider value={dispatch}>
{children}
</CarDispatchContext.Provider>
</CarStateContext.Provider>
);
};
export const CarStateContext = createContext();
export const CarDispatchContext = createContext();
现在,dispatch
自动可以访问state
via carReducer
,这非常好。即时还原!
好吧,无论如何,半个 Redux。我仍然缺少选择器,这是我的问题。鉴于上述上下文,我怎样才能最好地构建,例如,像getCarType()
这样的选择器只会“快速”返回到组件?
一个模糊的想法是这样的:
const CarStore = ({ children }) => {
const [state, dispatch] = useReducer(
carReducer,
[
{
type: 'fast',
mpg: 'bad',
},
],
);
// selectors, kind of.
const selectors = {
getType: () => { return state.type; },
getMpg: () => { return state.mpg; },
};
return (
<CarStateContext.Provider value={selectors}> // <- don't return state, return selectors
<CarDispatchContext.Provider value={dispatch}>
{children}
</CarDispatchContext.Provider>
</CarStateContext.Provider>
);
};
export const CarStateContext = createContext();
export const CarDispatchContext = createContext();
我猜这确实有效,但可能有更好的解决方案?
解决方案
这里最好和通用的解决方案是提供一个useSelector
由 redux 提供的简单 API,它接受一个回调并使用当前状态调用它并返回结果。
const CarStore = ({ children }) => {
const [state, dispatch] = useReducer(
carReducer,
[
{
type: 'fast',
mpg: 'bad',
},
],
);
const useSelector = (callback) => {
return callback(state)
};
return (
<CarStateContext.Provider value={{useSelector}}> // <- don't return state, return selectors
<CarDispatchContext.Provider value={dispatch}>
{children}
</CarDispatchContext.Provider>
</CarStateContext.Provider>
);
};
export const CarStateContext = createContext();
export const CarDispatchContext = createContext();
一旦你这样做了,你就可以将它用作任何组件,比如
const Comp = () => {
const {useSelector} = useContext(CarStateContext);
const type = useSelector((state) => { return state.type; })
const mpg = useSelector((state) => { return state.mpg; })
}
编辑 - 方法 2:在上述场景中,您需要useContext
单独使用,useSelector
为了避免它,您也可以将 useSelector 实现为钩子。此外,调度和状态不需要两个单独的上下文,您可以只使用一个
const CarStore = ({ children }) => {
const [state, dispatch] = useReducer(
carReducer,
[
{
type: 'fast',
mpg: 'bad',
},
],
);
const getValue = (callback) => {
return callback(state)
};
return (
<CarStateContext.Provider value={{getValue, dispatch}}> // <- don't return state, return selectors
{children}
</CarStateContext.Provider>
);
};
export const CarStateContext = createContext();
export const useSelector = (callback) => {
const {getValue} = useContext(CarStateContext);
return getValue(callback)
}
// Similarly dispatch can be provided like below
export const useDispatch = () => {
const {dispatch} = useContext(CarStateContext);
return dispatch
}
并在您的组件中使用它
import { useSelector, useDispatch } from 'path/to/useSelector'
const Comp = () => {
const type = useSelector((state) => { return state.type; })
const mpg = useSelector((state) => { return state.mpg; })
const dispatch = useDispatch();
}
推荐阅读
- laravel - 我如何限制任何路由的直接访问并抛出 404 异常,即使存在路由?
- javascript - 无法在导航标题上调用函数
- react-native - pod install 后 Nativemodule AsyncStorage 为空
- javascript - 虚拟主机中的代理形成外部IP?
- swift - SwiftUi - 背景无法更改/无法访问
- vue.js - elastic beanstalk 自定义构建过程
- pentaho - 更改报告页面中的默认 alflytics 徽标
- node.js - 使用 Auto Scaling 和 AWS 负载均衡器部署 nodejs
- firefox - 如何在 Firefox 70+ 的菜单上下文中恢复检查元素快捷方式 (Q)?
- angular - 将具有背景颜色的 Excel 工作表中的数据导出到标题行