如何在用于生成React列表标记的数组中正确调用Redux dispatch?
优化方案
直接全局引入store的写法主要存在几个问题:
- 服务端渲染场景下会导致单例store跨请求状态污染
- 单元测试时难以mock dispatch行为,会显著提升测试成本
- 违背React-Redux的设计原则,组件和全局store强耦合,不利于后续维护
方案1:使用useDispatch Hook动态绑定事件(推荐)
将配置项中的点击逻辑和dispatch行为解耦,配置里仅声明要触发的action,在组件内部通过React-Redux提供的useDispatch拿到dispatch实例后再绑定点击事件。
配置文件代码(可单独抽离,无需引入store)
const itemConfigs = [ { Icon: <SecurityIcon />, content: 'Activate Account', // 仅返回action对象,不直接执行dispatch action: () => openDialog(DIALOG_IDS.ACTIVATION) } // 其余配置项... ]; export default itemConfigs;
组件代码
import { useDispatch } from 'react-redux'; import itemConfigs from './config'; export default function Account() { const dispatch = useDispatch(); return ( <> {itemConfigs.map(({ Icon, content, action }) => ( <MenuItem onClick={() => dispatch(action())}> <ListItemIcon children={Icon} /> <ListItemContent children={content} /> </MenuItem> ))} </> ); }
该方案是官方推荐的标准写法,适配所有场景,同时支持测试时快速mock dispatch行为
方案2:将配置改为接收dispatch参数的工厂函数
如果你的配置项中点击逻辑非常复杂,希望把逻辑全部封装在配置文件中,可以将配置改为接收dispatch参数的生成函数,在组件内拿到dispatch后再生成最终的配置数组。
配置文件代码
export const generateItemConfigs = (dispatch) => [ { Icon: <SecurityIcon />, content: 'Activate Account', handleClick: () => dispatch(openDialog(DIALOG_IDS.ACTIVATION)) } // 其余配置项... ];
组件代码
import { useDispatch } from 'react-redux'; import { generateItemConfigs } from './config'; export default function Account() { const dispatch = useDispatch(); const items = generateItemConfigs(dispatch); return ( <> {items.map(({ Icon, content, handleClick}) => ( <MenuItem onClick={handleClick}> <ListItemIcon children={Icon} /> <ListItemContent children={content} /> </MenuItem> ))} </> ); }
该方案适合配置逻辑复杂、需要封装大量dispatch相关逻辑的场景
内容的提问来源于stack exchange,提问作者xandert.93
相关产品推荐
相关产品推荐

