React中使用useContext切换明暗模式报错:setState is not a function
修复React useContext明暗模式切换的“setState is not a function”错误
问题根源
- Context默认值结构不匹配:你创建
ModeContext时用空数组[]作为默认值,当组件不在ModeProvider包裹范围内时,useContext会返回这个空数组,解构得到的setDarkMode是undefined,调用它就会触发报错。 - 核心组件未被Provider包裹:
Layout组件直接使用useContext(ModeContext),但整个Layout没有被ModeProvider包裹,导致它和内部的Header都无法获取到正确的上下文状态更新函数。
修复步骤
1. 修正Context默认值
修改ModeProvider.js,将Context默认值改为和Provider提供的结构一致的数组,避免未被包裹时出现undefined:
import React, { useState } from "react" // 默认值改为[默认状态, 空函数],和Provider提供的结构匹配 export const ModeContext = React.createContext([false, () => {}]) const ModeProvider = ({ children }) => { const [darkMode, setDarkMode] = useState(true) return ( <ModeContext.Provider value={[darkMode, setDarkMode]}> {children} </ModeContext.Provider> ) } export default ModeProvider
2. 用ModeProvider包裹整个应用/核心组件
修改Layout.js,让ModeProvider包裹所有需要访问主题上下文的组件(包括ThemeProvider和内部内容):
import React, { useContext } from 'react' import Header from 'components/Header' import ModeProvider, { ModeContext } from 'context/ModeProvider' import { ThemeProvider } from 'styled-components' import darkTheme from './darkTheme' import lightTheme from './lightTheme' import GlobalStyles from './GlobalStyles' import useMetaDataQuery from '../../hooks/useMetaDataQuery' const Layout = ({ children }) => { return ( <ModeProvider> {/* 在Provider内部获取上下文值 */} {() => { const [darkMode] = useContext(ModeContext); const data = useMetaDataQuery(); return ( <ThemeProvider theme={darkMode ? darkTheme : lightTheme}> <GlobalStyles/> <Header siteTitle={data.title}/> {children} </ThemeProvider> ) }} </ModeProvider> ) }
如果你使用Gatsby,也可以在根配置文件(如gatsby-browser.js)中包裹Layout,效果一致:
// gatsby-browser.js示例 import ModeProvider from './src/context/ModeProvider' import Layout from './src/components/Layout' export const wrapPageElement = ({ element, props }) => { return ( <ModeProvider> <Layout {...props}>{element}</Layout> </ModeProvider> ) }
3. 保留原有组件逻辑
你的ModeButton和Header的代码逻辑是正确的,只要它们处于ModeProvider的子组件范围内,就能正确获取setDarkMode函数,点击切换时不会再报错。
额外说明
- 确保所有需要访问主题上下文的组件都在
ModeProvider的子组件范围内,否则会使用默认值。 - 用空函数作为默认值的目的是,即使组件意外不在Provider范围内,调用
setDarkMode也不会抛出错误,只是不会触发状态更新。
内容的提问来源于stack exchange,提问作者github.arief
相关产品推荐
相关产品推荐

