You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中使用useContext切换明暗模式报错:setState is not a function

修复React useContext明暗模式切换的“setState is not a function”错误

问题根源

  1. Context默认值结构不匹配:你创建ModeContext时用空数组[]作为默认值,当组件不在ModeProvider包裹范围内时,useContext会返回这个空数组,解构得到的setDarkMode是undefined,调用它就会触发报错。
  2. 核心组件未被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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 10:35:12