如何从使用Hooks的React函数组件导出函数至其他组件?
解决React Hooks组件中复用含useDispatch逻辑的函数问题
你遇到的问题核心在于:useDispatch是React Hook,只能在React组件函数或者自定义Hook的顶层调用,不能直接放到普通的function.js这类文件里——这违反了Hook的使用规则,所以才会抛出大量错误。下面给你两种可行的解决方案,帮你安全复用toggleDrawer函数:
方案一:创建自定义Hook封装抽屉切换逻辑
自定义Hook是React官方推荐的复用Hook相关逻辑的方式,完全符合Hook规则。
步骤1:创建自定义Hook文件
新建一个useDrawerToggle.js文件,把抽屉切换的逻辑封装进去:
import { useDispatch } from 'react-redux'; import { REDUCERS } from '../../Config/config'; export const useDrawerToggle = () => { const dispatch = useDispatch(); // 原toggleDrawer逻辑不变,只是放到自定义Hook里 const toggleDrawer = (side, open) => event => { if (event.type === 'keydown' && (event.key === 'Tab' || event.key === 'Shift')) { return; } dispatch({ type: REDUCERS.TOGGLE_DRAWER, payload: open }); }; return toggleDrawer; };
步骤2:在Layout组件中使用
修改你的Layout组件,导入并使用这个自定义Hook:
import React from 'react' import { useSelector } from 'react-redux' import { useDrawerToggle } from './useDrawerToggle'; // 导入自定义Hook import Header from '../Header/header' import DrawerItems from '../DrawerItems/drawerItems' import { REDUCERS } from '../../Config/config' import Container from '@material-ui/core/Container' import Drawer from '@material-ui/core/Drawer' import { makeStyles } from '@material-ui/core/styles' const useDrawerStyles = makeStyles({ paper: { width: '175px', padding: '10px' } }) const Layout = props => { const { isDrawerOpened } = useSelector(state => { return { ...state.interface_reducer } }) const drawerClasses = useDrawerStyles() const toggleDrawer = useDrawerToggle(); // 获取复用的toggleDrawer函数 return ( <Container> <React.Fragment> <Header/> <Drawer classes={{paper: drawerClasses.paper}} open={isDrawerOpened} onClose={toggleDrawer('left', false)} > <DrawerItems/> </Drawer> { props.children } </React.Fragment> </Container> ) } export default Layout
步骤3:在其他组件中复用
比如你有一个需要打开抽屉的按钮组件,直接导入自定义Hook即可:
import { useDrawerToggle } from '../path/to/useDrawerToggle'; const OpenDrawerButton = () => { const toggleDrawer = useDrawerToggle(); return ( <button onClick={toggleDrawer('left', true)}>打开侧边抽屉</button> ); }; export default OpenDrawerButton;
方案二:结合Redux Action Creator(进阶优化)
如果你的Redux项目遵循规范,建议把Action逻辑单独抽离,让代码更易维护和测试:
步骤1:创建Action Creator文件
新建interfaceActions.js,定义抽屉切换的Action:
import { REDUCERS } from '../Config/config'; export const toggleDrawer = (open) => { return { type: REDUCERS.TOGGLE_DRAWER, payload: open }; };
步骤2:修改自定义Hook使用Action Creator
更新useDrawerToggle.js,使用抽离的Action:
import { useDispatch } from 'react-redux'; import { toggleDrawer as toggleDrawerAction } from './interfaceActions'; export const useDrawerToggle = () => { const dispatch = useDispatch(); const toggleDrawer = (side, open) => event => { if (event.type === 'keydown' && (event.key === 'Tab' || event.key === 'Shift')) { return; } dispatch(toggleDrawerAction(open)); // 调用Action Creator }; return toggleDrawer; };
后续组件的使用方式和方案一完全一致,这样做的好处是:Action逻辑集中管理,后续如果需要修改抽屉切换的逻辑(比如增加参数、异步操作),只需要修改Action Creator即可,不用改动所有使用的组件。
关键注意事项
- 永远遵守Hook规则:只能在组件或自定义Hook的顶层调用Hook,不能在循环、条件判断、嵌套函数里调用,否则会触发React的错误提示。
- 自定义Hook的命名必须以
use开头,这是React识别自定义Hook的约定,也能让ESLint帮你检查Hook规则的合规性。
内容的提问来源于stack exchange,提问作者MMaicki
相关产品推荐
相关产品推荐

