Let's say I have this context:
export const ThemeContext = createContext();
export function ThemeWrapper({ children }) {
const sharedState = {
darkMode: false,
};
return (
<ThemeContext.Provider value={sharedState}>
{children}
</ThemeContext.Provider>
);
}
export function useThemeContext() {
return useContext(ThemeContext);
}
Which I can access on _document.js
like this:
import Document, { Html, Head, Main, NextScript } from "next/document";
import { ThemeWrapper, ThemeContext } from "../context/theme";
class MyDocument extends Document {
static contextType = ThemeContext;
render() {
console.log("theme", this.context);
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
class Wrapped extends Document {
render() {
return (
<ThemeWrapper>
<MyDocument />
</ThemeWrapper>
);
}
}
export default Wrapped;
Now I also want to access this context from a page:
import { useThemeContext } from "../context/theme";
const SomePage = () => {
const theme = useThemeContext();
console.log("theme", theme);
return (
<div>Hi, I'm a page</div>
);
};
_document.js
logs out theme { darkMode: false }
on the Next.js console when the page is first loaded but SomePage
logs out theme undefined
on the Chrome console everytime you navigate to it.
Any suggestions?
I need to toggle some class on the html
tag depending on this context. Trying to manually toggle dark mode using Tailwind CSS.
Let's say I have this context:
export const ThemeContext = createContext();
export function ThemeWrapper({ children }) {
const sharedState = {
darkMode: false,
};
return (
<ThemeContext.Provider value={sharedState}>
{children}
</ThemeContext.Provider>
);
}
export function useThemeContext() {
return useContext(ThemeContext);
}
Which I can access on _document.js
like this:
import Document, { Html, Head, Main, NextScript } from "next/document";
import { ThemeWrapper, ThemeContext } from "../context/theme";
class MyDocument extends Document {
static contextType = ThemeContext;
render() {
console.log("theme", this.context);
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
class Wrapped extends Document {
render() {
return (
<ThemeWrapper>
<MyDocument />
</ThemeWrapper>
);
}
}
export default Wrapped;
Now I also want to access this context from a page:
import { useThemeContext } from "../context/theme";
const SomePage = () => {
const theme = useThemeContext();
console.log("theme", theme);
return (
<div>Hi, I'm a page</div>
);
};
_document.js
logs out theme { darkMode: false }
on the Next.js console when the page is first loaded but SomePage
logs out theme undefined
on the Chrome console everytime you navigate to it.
Any suggestions?
I need to toggle some class on the html
tag depending on this context. Trying to manually toggle dark mode using Tailwind CSS.
- So is the new page wrapped inside a ThemeWrapper? – Keith Commented Feb 12, 2021 at 14:13
- Instead of wrapping the document try wrapping Main in ThemeWrapper. When you wrap the native document from next, I have a feeling that might not work. – Mellet Commented Feb 12, 2021 at 14:13
- You can also try creating a custom app and adding your context wrapper there. nextjs/docs/advanced-features/custom-app – Mellet Commented Feb 12, 2021 at 14:17
- 2 You should use the ThemeWrapper in a custom App not Document – nip Commented Feb 12, 2021 at 14:19
- @Keith Nope, do I need to? I thought that wrapping the document would give me access anywhere down the tree. – Camilo Commented Feb 12, 2021 at 14:35
1 Answer
Reset to default 6 +50Wrapping _document
with ThemeWrapper
doesn't give you access to the context inside pages (probably because it's only rendered in the server), you will need to wrap _app
for that. Just note that _document
will not re-render on context state changes.
For this specific use case, an alternative is to use next-themes
.