In order to do this, you want your theme to be stored in a state
somewhere such that it can be updated and those updates will trigger re-renders.
We can use two separate context providers: the styled-components ThemeProvider
and our own context which will provide some sort of callback which is used to update the theme state.
Here's some sample code which should point you in the right direction.
We create a Context
for the theme update function. We give it a default value which logs an error.
const ThemeUpdateContext = createContext(
(theme: DefaultTheme) => console.error("attempted to set theme outside of a ThemeUpdateContext.Provider")
)
We make a custom theme provider that stores the theme in local state. This wraps its children
in providers for both the theme and the update function.
export const MyThemeProvider: React.FC = ({ children }) => {
// store the entire theme as state, using your constant as the initial state
const [myTheme, setMyTheme] = useState(theme);
return (
<ThemeProvider theme={myTheme}>
<ThemeUpdateContext.Provider value={setMyTheme}>
{children}
</ThemeUpdateContext.Provider>
</ThemeProvider>
)
}
We can then use those contexts to make updates from any component inside the MyThemeProvider
. You can, for example, push changes to the theme based on a value retrieved from the API or a cookie from localStorage
.
Here's a very arbitrary example:
const SampleComponent = () => {
const updateTheme = useContext(ThemeUpdateContext);
const currentTheme = useContext(ThemeContext);
return (
<button
onClick={() => updateTheme({
...currentTheme,
text: {
...currentTheme.text,
main: 'blue',
}
})}
>
Make Main Text Blue
</button>
)
}
Typescript Playground Link
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…