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

Next.js+Material UI点击触发API调用后运行时动态切换全局主题咨询

解决方案

核心逻辑说明

  1. MUI 内置的 ThemeProvider 仅负责向下传递主题配置,不提供更新主题的内置方法,所以根组件用 useState 存储主题状态是必须的,但完全可以不用自定义 Context,直接通过 Next.js 页面 props 传递修改方法即可。
  2. 不能在普通异步函数内部调用 useContext 是 React Hook 的硬性调用规则限制,Hook 只能在函数组件顶层调用,所以需要先在组件内拿到更新方法,再传入异步函数使用。

修改后的实现代码

1. _app.ts 去掉自定义 Context

export default function MyApp(props: any) {
    const { Component, pageProps } = props;
    const [theme, setTheme] = useState(muiTheme);

    React.useEffect(() => {
        // Remove the server-side injected CSS.
        const jssStyles = document.querySelector('#jss-server-side');
        if (jssStyles && (jssStyles.parentElement !== null)) {
            jssStyles.parentElement.removeChild(jssStyles);
        }
    }, []);

    return (
        <React.Fragment>
            <Head>
                <title>My page</title>
                <meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width" />
            </Head>
            <ThemeProvider theme={theme}>
                <CssBaseline />
                {/* 直接把setTheme传给所有页面组件 */}
                <Component {...pageProps} setTheme={setTheme} />
            </ThemeProvider>
        </React.Fragment>
    );
}

2. 页面组件调整异步逻辑

// 页面组件内代码
export default function RoomPage(props) {
  // 组件顶层先拿到setTheme方法
  const { setTheme } = props;

  // 异步方法定义在组件内部,直接调用拿到的setTheme
  async function updateRoom(room: any, flowActionId: any) {
    try {
      const response = await axios.put(`/api/room/${room.id}`, {
        flow_action_id: Number(flowActionId)
      });
      // 从接口返回结果取自定义颜色
      const newPrimaryColor = response.data.themeColor || '#123123';
      const leTheme = createTheme({
        palette: {
          primary: {
            main: newPrimaryColor,
          }
        },
      });
      // 直接更新全局主题
      setTheme(leTheme);
    } catch (error) {
      console.error(error);
    }
  }

  return (
    <Button
      onClick={() => updateRoom(room, flowActionId)}
      // 其他按钮属性
    />
  )
}

补充说明

如果项目组件层级深,不想一层层传递 setTheme,你原来的自定义 Context 方案是 React 全局状态共享的标准实现,并不算冗余,更适合中长期维护。如果不想用 Context 也不想逐层传参,可以引入轻量状态管理库(比如 Zustand)存储 theme 状态,代码会更简洁。

内容的提问来源于stack exchange,提问作者Electrik Bunny

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 05:18:01