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

使用SolidJS children辅助方法后Theme Provider失效,setTheme非函数

问题:ThemeProvider修改后报错“setTheme不是函数”

原本的Solid.js ThemeProvider代码可以正常工作,但添加const c = children(() => props.children);并将返回的子元素改为{c()}后,出现**“setTheme不是函数”**的错误。

原正常代码

import { Accessor, JSXElement, Setter, children, createContext, createEffect, createSignal, onMount, useContext } from "solid-js";

import constants from "@/constants";

type TThemeProviderProps = {
  children: JSXElement;
  defaultTheme: string;
};

type TThemeContext = [Accessor<string>, Setter<string>];

const ThemeKey = "stk-auth-theme";


const ThemeProvider = (props: TThemeProviderProps) => {
  const [theme, setTheme] = createSignal<string>(props.defaultTheme);

  onMount(() => {
    // 读取缓存
    const cachedTheme = localStorage.getItem(ThemeKey);
    if (cachedTheme) {
      setTheme(cachedTheme);
    } else {
      const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
      setTheme(prefersDark ? "dark" : "light")
    }
  });

  createEffect(() => {
    document.documentElement.classList.toggle(constants.DARK_MODE, theme() === constants.DARK_MODE);
    // 写入缓存
    localStorage.setItem(ThemeKey, theme());
  });

  const values: TThemeContext = [theme, setTheme];

  return <ThemeContext.Provider value={values}>{props.children}</ThemeContext.Provider>;
};

export const ThemeContext = createContext<TThemeContext>([() => "", undefined]);

export default ThemeProvider;

export const useTheme = () => {
  return useContext(ThemeContext);
};

修改后报错的代码

import { Accessor, JSXElement, Setter, children, createContext, createEffect, createSignal, onMount, useContext } from "solid-js";

import constants from "@/constants";

type TThemeProviderProps = {
  children: JSXElement;
  defaultTheme: string;
};

type TThemeContext = [Accessor<string>, Setter<string>];

const ThemeKey = "stk-auth-theme";


const ThemeProvider = (props: TThemeProviderProps) => {
  const c = children(() => props.children);
  const [theme, setTheme] = createSignal<string>(props.defaultTheme);

  onMount(() => {
    // 读取缓存
    const cachedTheme = localStorage.getItem(ThemeKey);
    if (cachedTheme) {
      setTheme(cachedTheme);
    } else {
      const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
      setTheme(prefersDark ? "dark" : "light")
    }
  });

  createEffect(() => {
    document.documentElement.classList.toggle(constants.DARK_MODE, theme() === constants.DARK_MODE);
    // 写入缓存
    localStorage.setItem(ThemeKey, theme());
  });

  const values: TThemeContext = [theme, setTheme];

  return <ThemeContext.Provider value={values}>{c()}</ThemeContext.Provider>;
};

export const ThemeContext = createContext<TThemeContext>([() => "", undefined]);

export default ThemeProvider;

export const useTheme = () => {
  return useContext(ThemeContext);
};

原因分析与修复

核心原因

在Solid.js中,children()函数返回的是响应式访问器,但直接调用c()会强制子元素提前求值,打破了Solid.js的渲染顺序:子组件会在ThemeProvider的Context值(包含setTheme的数组)完成初始化前,就通过useTheme()获取Context,此时拿到的是Context的默认值[() => "", undefined],自然会报错“setTheme不是函数”。

另外,Solid.js中直接使用props.children即可处理绝大多数子元素场景,children()仅用于子元素是动态函数式内容(比如children={(theme) => <div>{theme}</div>})的情况,你的场景完全不需要额外包裹。

修复方案

移除children()的多余使用,直接恢复使用{props.children}即可,修复后代码如下:

import { Accessor, JSXElement, Setter, createContext, createEffect, createSignal, onMount, useContext } from "solid-js";

import constants from "@/constants";

type TThemeProviderProps = {
  children: JSXElement;
  defaultTheme: string;
};

type TThemeContext = [Accessor<string>, Setter<string>];

const ThemeKey = "stk-auth-theme";

const ThemeProvider = (props: TThemeProviderProps) => {
  const [theme, setTheme] = createSignal<string>(props.defaultTheme);

  onMount(() => {
    const cachedTheme = localStorage.getItem(ThemeKey);
    if (cachedTheme) {
      setTheme(cachedTheme);
    } else {
      const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
      setTheme(prefersDark ? "dark" : "light")
    }
  });

  createEffect(() => {
    document.documentElement.classList.toggle(constants.DARK_MODE, theme() === constants.DARK_MODE);
    localStorage.setItem(ThemeKey, theme());
  });

  const values: TThemeContext = [theme, setTheme];

  return <ThemeContext.Provider value={values}>{props.children}</ThemeContext.Provider>;
};

export const ThemeContext = createContext<TThemeContext>([() => "", undefined]);

export default ThemeProvider;

export const useTheme = () => {
  return useContext(ThemeContext);
};

内容的提问来源于stack exchange,提问作者Adharsh M

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 20:42:37