首页 > 解决方案 > 从 onClick 事件进行 api 调用后在运行时更改应用程序主题

问题描述

我是 next.js 的新手,我会做出反应并且无法解决这个问题。我的应用程序要求我在进行 api 调用后在运行时更改页面的整个主题。我正在使用 next.js 反应和材料 UI。

我试图做的是创建一个反应上下文并在其中一个嵌套子项中使用它,但不幸的是我不能在 onClick 函数中使用它,这违背了我想要做的事情的目的。

理想流量

  1. 在 _app.ts 中声明一个主题对象作为 ThemeProvider 的参数
  2. 在其中一个页面的按钮中有一个 onClick 事件,该事件将对 api 进行异步调用并检索颜色值
  3. 根据该值创建主题对象
  4. 将应用程序主题交换为新主题。

到目前为止我得到的是这个,但它看起来很笨重。

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

    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={value.theme}>

// IS THERE A WAY NOT TO USE MY OWN ThemeContext.Provider and use MUI Theme provider instead to change a theme?

                <ThemeContext.Provider value={value}>
                    {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
                    <CssBaseline />
                    <Component {...pageProps} />
                </ThemeContext.Provider>
            </ThemeProvider>

        </React.Fragment>
    );
}

现在在 nextjs 的一个页面中,我有一个按钮,可以在 updateRoom 方法中进行 api 调用。但是在该函数内部,我无法使用 useContext 挂钩。

有没有更好的方法来解决这个问题?

<Button
            onClick={() => updateRoom(room, flowActionId)}
            ...

我想在 updateRoom 方法中做的是这个

async function updateRoom(room: any, flowActionId: any) {
    try {
        const response = await axios.put(`/api/room/${room.id}`,
            {
                flow_action_id: Number(flowActionId)
            });



    const leTheme = createTheme({
        palette: {
          primary: {
            main: '#123123', <--- parse my api call and set this color
          }
        },
      });

      const { theme, setTheme } = useContext(ThemeContext);
      setTheme(leTheme); <--- set the app theme here.



    } catch (error) {
        console.error(error);
    }
}

标签: reactjsmaterial-uinext.js

解决方案


试着看看我的代码。我试着做同样的事情

我已经像这样创建了一个单独的 ThemeContext 文件..

const ThemeContext = createContext();

const ThemeProvide = (props) => {
  const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
  const [theme, setTheme] = useState({
    primary: "#003e7e",
    secondary: "#ADEFD1FF",
    type: prefersDarkMode ? "dark" : "light",
    background: "#fafafa",
    paper: "#ffffff",
  });

  const themePalette = createMuiTheme({
    palette: {
      primary: {
        main: theme.primary,
      },
      secondary: {
        main: theme.secondary,
      },
      background: {
        default: theme.background,
        paper: theme.paper,
      },
      type: theme.type,
    },
  });
   
  return (
    <ThemeContext.Provider value={[theme, setTheme]}>
      <ThemeProvider theme={themePalette}>
        <CssBaseline />
       {props.children}
      </ThemeProvider>
    </ThemeContext.Provider>
  );
};

export { ThemeContext, ThemeProvide };

现在我用这个 ThemeProvide 组件包装整个 _app.js //注意黑白 ThemeProvider 和 ThemeProvide 组件的区别我相信你可以比我更好地命名它

import { ThemeProvide } from "../state/theme";

 const MyApp = ({ Component, pageProps }) => {
      useEffect(() => {
        const jssStyles = document.querySelector("#jss-server-side");
        if (jssStyles) {
          jssStyles.parentElement.removeChild(jssStyles);
        }
      }, []);
      return (
        <>
            <ThemeProvide>
              <Component {...pageProps} />
            </ThemeProvide>
        </>
      );
    };
    
    export default MyApp;

现在我可以在我的任何页面或组件中使用 ThemeContext

像这样

const [theme,setTheme ] = useContext(ThemeContext)
//Use setTheme to change your Theme

推荐阅读