React Context报错:notifContext.dispatch不是函数问题排查
解决React Context中dispatch未定义的问题
问题根源
- 自定义Context未暴露dispatch:在
context.js的Provider value中,只传递了state和绑定后的actions,没有把useReducer返回的dispatch包含进去,导致组件中无法获取到dispatch方法。 - useContext使用错误:组件中用数组解构
const [notifContext] = useContext(NotifContext)获取上下文,而useContext实际返回的是对象,这种写法会导致拿到的notifContext是undefined(对象解构数组会取索引0的值,而上下文对象不是数组)。
解决方案
1. 修改context.js,暴露dispatch
在Provider的value中添加dispatch属性:
import React, {useReducer} from 'react'; export default (reducer, actions, defaultValue) => { const Context = React.createContext(); const Provider = ({children}) => { const [state, dispatch] = useReducer(reducer, defaultValue); const boundActions = {}; for (let key in actions) { boundActions[key] = actions[key](dispatch); } return ( <Context.Provider value={{ state, dispatch, // 新增:将dispatch暴露到上下文中 ...boundActions, }}> {children} </Context.Provider> ); }; return {Context, Provider}; };
2. 修正组件中useContext的用法
去掉数组解构,直接获取上下文对象(或按需解构属性):
import {Context as NotifContext} from '../../context/NotifContext'; // 错误写法:const [notifContext] = useContext(NotifContext); const notifContext = useContext(NotifContext); // 正确写法 useEffect(() => { if (notifContext?.state?.errorMessage) { setToast( Toast.show(notifContext?.state?.errorMessage, { duration: Toast.durations.SHORT, position: Toast.positions.CENTER, onHidden: () => notifContext?.dispatch({type: 'clear_error_message'}), }), ); } else if (toast) { Toast.hide(toast); } }, [notifContext?.state?.errorMessage]);
优化建议(可选)
为了保持Context的封装性,建议在notifContext.js中封装action方法,避免组件直接调用dispatch:
修改notifContext.js:
const defaultValue = { errorMessage: '', notifCount: [0], notifications: [], }; const notifReducer = (state, action) => { switch (action.type) { case 'error_1': return { ...state, errorMessage: action.payload, }; case 'clear_error_message': return { ...state, errorMessage: '', }; default: return state; // 新增default分支,避免无匹配action时返回undefined } }; // 封装action creators const actions = { clearErrorMessage: (dispatch) => () => { dispatch({type: 'clear_error_message'}); }, // 其他业务action... }; export const {Provider, Context} = context( notifReducer, actions, defaultValue, );
组件中直接调用封装好的方法:
import {Context as NotifContext} from '../../context/NotifContext'; const { state, clearErrorMessage } = useContext(NotifContext); useEffect(() => { if (state?.errorMessage) { setToast( Toast.show(state.errorMessage, { duration: Toast.durations.SHORT, position: Toast.positions.CENTER, onHidden: clearErrorMessage, // 直接调用封装好的方法 }), ); } else if (toast) { Toast.hide(toast); } }, [state?.errorMessage]);
内容的提问来源于stack exchange,提问作者jdez
相关产品推荐
相关产品推荐

