【发布时间】:2021-12-31 14:41:12
【问题描述】:
使用React's Context api 在我的Next.js 应用程序上实现了“暗模式”功能。
在开发过程中一切正常,但是在构建版本上出现了与Context provider相关的问题——全局状态显示为undefined,无法处理。
_app.tsx 被 ThemeProvider 这样包裹:
// React & Next hooks
import React, { useEffect } from "react";
import type { AppProps } from "next/app";
import { useRouter } from "next/router";
// Irrelevant imports
// Global state management
import { Provider } from "react-redux";
import store from "../redux/store";
import { AuthProvider } from "../context/UserContext";
import { ThemeProvider } from "../context/ThemeContext";
// Components
import Layout from "../components/Layout/Layout";
import Footer from "../components/Footer/Footer";
// Irrelevant code
function MyApp({ Component, pageProps }: AppProps) {
const router = useRouter();
// Applying different layouts depending on page
switch (Component.name) {
case "HomePage":
return (
<Provider store={store}>
<ThemeProvider>
<AuthProvider>
<Component {...pageProps} />
<Footer color="fff" />
</AuthProvider>
</ThemeProvider>
</Provider>
);
case "PageNotFound":
return (
<>
<Component {...pageProps} />
<Footer color="#f2f2f5" />
</>
);
default:
// Irrelevant code
}
}
export default MyApp;
ThemeContext 正确导出其Provider 和Context:
import { createContext, ReactNode, useState, useEffect } from "react";
type themeContextType = {
darkMode: boolean | null;
toggleDarkMode: () => void;
};
type Props = {
children: ReactNode;
};
// Checks for user's preference.
const getPrefColorScheme = () => {
return !window.matchMedia
? null
: window.matchMedia("(prefers-color-scheme: dark)").matches;
};
// Gets previously stored theme if it exists.
const getInitialMode = () => {
const isReturningUser = "dark-mode" in localStorage; // Returns true if user already used the website.
const savedMode = localStorage.getItem("dark-mode") === "true" ? true : false;
const userPrefersDark = getPrefColorScheme(); // Gets user's colour preference.
// If mode was saved ► return saved mode else get users general preference.
return isReturningUser ? savedMode : userPrefersDark ? true : false;
};
export const ThemeContext = createContext<themeContextType>(
{} as themeContextType
);
export const ThemeProvider = ({ children }: Props) => {
// localStorage only exists on the browser (window), not on the server
const [darkMode, setDarkMode] = useState<boolean | null>(null);
// Getting theme from local storage upon first render
useEffect(() => {
setDarkMode(getInitialMode);
}, []);
// Prefered theme stored in local storage
useEffect(() => {
localStorage.setItem("dark-mode", JSON.stringify(darkMode));
}, [darkMode]);
const toggleDarkMode = () => {
setDarkMode(!darkMode);
};
return (
<ThemeContext.Provider value={{ darkMode, toggleDarkMode }}>
{children}
</ThemeContext.Provider>
);
};
负责更新darkMode 状态的ThemeToggler 在开发过程中正常运行(主题切换和正确值console.loged 在点击时),但是它在生产过程中没有做任何事情(console.logs 和@987654337 @状态):
import React, { FC, useContext } from "react";
import { ThemeContext } from "../../context/ThemeContext";
const ThemeToggler: FC = () => {
const { darkMode, toggleDarkMode } = useContext(ThemeContext);
const toggleTheme = () => {
console.log(darkMode) // <--- darkMode is undefined during production
toggleDarkMode();
};
return (
<div className="theme-toggler">
<i
className={`fas ${darkMode ? "fa-sun" : "fa-moon"}`}
data-testid="dark-mode"
onClick={toggleTheme}
></i>
</div>
);
};
export default ThemeToggler;
我在发布之前查看的解决方案/建议无济于事。
React Context API undefined in production — react 和 react-dom 在同一版本上。
提前致谢。
附:对于那些想知道为什么我同时使用 Redux 和 Context 进行全局状态管理的人:
-
Context最适合低频和简单的状态更新,例如 themes 和 authentication。 -
Redux除了提供更好的调试工具——Redux DevTools,更适合高频和复杂的状态更新。
P.S.2 是的,在性能方面,安装 FontAwesome 的依赖项比使用 CDN 更好。
【问题讨论】:
标签: reactjs typescript next.js react-context