[英]Ad blocker block affiliate page on production but works fine on development?
[英]NextJS: Context values undefined in production (works fine in development)
使用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
state 的ThemeToggler
在开发过程中正常运行(主题切换和正确的值console.log
在点击时),但是它在生产过程中没有做任何事情( console.log
是undefined
的状态):
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 上下文 API 在生产中未定义——react和react
react-dom
在同一个版本上。
提前致谢。
PS 对于那些想知道为什么我同时使用Redux
和Context
进行全局 state 管理的人:
Context
最适合低频和简单的 state 更新,例如主题和身份验证。
Redux
除了提供更好的调试工具Redux DevTools
之外,更适合高频和复杂的state更新。
PS2 是的,安装 FontAwesome 的依赖项而不是使用 CDN 更好——性能方面。
感谢分享代码。 它写得很好。 通过阅读它,我没有看到任何问题。 根据您的组件拓扑,只要您的ThemeToggler
定义在任何页面组件下,您的darkMode
就不能是undefined
。
这是您的站点拓扑
<MyApp>
<Provider>
// A. will not work
<ThemeProvider>
<HomePage>
// B. should work
</HomePage>
</ThemeProvider>
// C. will not work
</Provider>
</MyApp>
虽然您的ThemeProvider
是一个自定义提供程序,但在ThemeContext.Provider
内部是用值{{ darkMode, toggleDarkMode }}
的。 所以理论上你不能undefined
除非你的组件ThemeToggler
不在HomePage
组件下。 我标记了两个非工作位置,任何放在位置 A 或 C 下的组件都会给你undefined
。
由于您有HomePage
的条件,因此如果您在其他页面上,您可能会遇到此问题。 所以一般来说你应该把ThemeProvider
包裹在你的路由器之上。
<ThemeProvider>
<AuthProvider>
{Component.name != "PageNotFound" && (
<Component {...pageProps} />
)}
</AuthProvider>
</ThemeProvider>
你明白了,在你启动路由器之前,你想首先通过一个主题总是存在的层 go。
您可以通过执行以下测试来确认是否是这种情况。
function MyApp({ Component, pageProps }: AppProps) {
return (
<ThemeProvider>
<AuthProvider>
<Component {...pageProps} />
</AuthProvider>
</ThemeProvider>
)
}
如果这在生产中有效,则可以确认。 说实话,这个问题在开发中也存在,不过可能是你的路由变化太快,一般都会隐藏这些问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.