TS React中useContext失效,出现无效Hook调用错误求助
解决React Context的无效Hook调用错误
错误根源
你在React.createContext的默认值中直接调用了useSharedValue这个Hook,这违反了React Hook的核心规则:Hook只能在React组件函数的顶层、或自定义Hook的顶层调用,不能在模块全局作用域、普通函数里执行。createContext是在模块加载时就运行的,此时根本不在React的组件渲染流程中,所以会触发"无效Hook调用"错误。
修复步骤
修正Context的默认值定义
把默认值里的useSharedValue调用替换为符合类型的占位值,避免在全局作用域调用Hook:// types.ts type Score = { correct: number; incorrect: number; }; export type ReactQuizContextType = { check: SharedValue<string>; activeIndex: SharedValue<number>; direction: SharedValue<string>; redo: boolean; setRedo: React.Dispatch<React.SetStateAction<boolean>>; score: Score; setScore: React.Dispatch<React.SetStateAction<Score>>; }; // 用类型断言给SharedValue设置符合结构的占位值,避免调用Hook export const ReactQuizContext = React.createContext<ReactQuizContextType>({ check: { value: "wrong" } as SharedValue<string>, activeIndex: { value: 0 } as SharedValue<number>, direction: { value: "vertical" } as SharedValue<string>, redo: false, setRedo: () => {}, score: { correct: 0, incorrect: 0 }, setScore: () => {}, }); export const useReactQuizContext = () => React.useContext(ReactQuizContext);在Provider所在组件内创建Hook值
所有需要注入Context的Hook(useSharedValue、useState等),必须在Provider所在的组件内部顶层创建,确保在React渲染流程中调用:// ReactQuiz组件 const ReactQuiz = () => { // 在此处创建所有Context需要的Hook值 const check = useSharedValue("wrong"); const activeIndex = useSharedValue(0); const direction = useSharedValue("vertical"); const [redo, setRedo] = React.useState(false); const [score, setScore] = React.useState<Score>({ correct: 0, incorrect: 0 }); // 其他业务逻辑示例 const onCorrect = () => { setScore(prev => ({ ...prev, correct: prev.correct + 1 })); }; const onIncorrect = () => { setScore(prev => ({ ...prev, incorrect: prev.incorrect + 1 })); }; return ( <ReactQuizContext.Provider value={{ score, setScore, redo, setRedo, activeIndex, direction, check }} > <GestureHandlerRootView style={styles.container}> <StatusBar style="auto" hidden /> <GestureDetector gesture={Gesture.Exclusive(flingUp, flingDown)}> <View style={[styles.dataContainer]} pointerEvents="box-none"> {data.map((item, index) => ( <Card info={item} key={item.id} index={index} activeIndex={activeIndex} totalLength={data.length - 1} direction={direction} onCorrect={onCorrect} onIncorrect={onIncorrect} /> ))} </View> </GestureDetector> </GestureHandlerRootView> </ReactQuizContext.Provider> ); };
额外提醒
- 确保所有使用
useReactQuizContext的组件,都被ReactQuizContext.Provider包裹,否则会拿到默认的占位值,可能导致异常。 - 若想避免误用默认值,可以把Context类型改为可选,然后在自定义Hook里做校验:
export const ReactQuizContext = React.createContext<ReactQuizContextType | undefined>(undefined); export const useReactQuizContext = () => { const context = React.useContext(ReactQuizContext); if (!context) { throw new Error("useReactQuizContext must be used within a ReactQuizContext.Provider"); } return context; };
内容的提问来源于stack exchange,提问作者Mathew
相关产品推荐
相关产品推荐

