I create a file called ThemeContext:
import { createContext, useState } from "react";
import PropTypes from "prop-types";
import { DARK_THEME, LIGHT_THEME } from "../constants/themeConstants";
interface ThemeContextType {
theme: string;
toggleTheme: () => void;
}
export const ThemeContext = createContext<ThemeContextType>({
theme: LIGHT_THEME,
toggleTheme: () => {}
});
export const ThemeProvider: React.FC<{}> = ({ children }: any) => {
const [theme, setTheme] = useState<string>(
window.localStorage.getItem("themeMode") || LIGHT_THEME
);
window.localStorage.setItem("themeMode", theme);
const toggleTheme = () => {
setTheme((prevTheme) =>
prevTheme === LIGHT_THEME ? DARK_THEME : LIGHT_THEME
);
window.localStorage.setItem("themeMode", theme);
};
return (
<ThemeContext.Provider
value={{
theme,
toggleTheme,
}}
>
{children}
</ThemeContext.Provider>
);
};
ThemeProvider.propTypes = {
children: PropTypes.node.isRequired,
};
and this is where I am using the theme provider :
import "./App.scss";
import { ThemeProvider } from "./context/ThemeContext";
import Admin from "./routes/admin/Admin";
import Global from "./routes/global/Global";
function App() {
return (
<div className="App">
<Global />
<ThemeProvider>
<Admin></Admin>
</ThemeProvider>
</div>
);
}
export default App;
but I got an error which is this: Type '{ children: Element; }' has no properties in common with type 'IntrinsicAttributes'.ts(2559) (alias) module ThemeProvider (alias) const ThemeProvider: React.FC<{}> import ThemeProvider
I tried to understand the issue but it seems like the ThemeProvider doesn' accept any element wrapped by it. I hope someone help me
You have typed the ThemeProvider
component to have no props, but are passing children props when wrapping components. The any
type conflicts with the {}
that was passed in React.FC<{}>
.
Use the React.PropsWithChildren
type.
export const ThemeProvider: React.FC<React.PropsWithChildren<{}>> = ({
children
}) => {
...
};
or just
export const ThemeProvider = ({ children }: React.PropsWithChildren<{}>) => {
...
};
If you had other component props they would be passed to PropsWithChildren
.
interface ThemeProviderProps {
someProp: string;
someNumber: number;
}
export const ThemeProvider = (
{ children, someProp, someNumber }: React.PropsWithChildren<{ThemeProviderProps}>
) => {
...
};
You will also want to use an initializer function to set the initial theme
state, and a useEffect
hook to issue the side-effect to update localStorage when the theme
state value changes.
Example:
import { PropsWithChildren } from 'react';
export const ThemeProvider = ({ children }: PropsWithChildren<{}>) => {
const [theme, setTheme] = useState<string>(
() => window.localStorage.getItem("themeMode") || LIGHT_THEME
);
useEffect(() => {
window.localStorage.setItem("themeMode", theme);
}, [theme]);
...
};