Goal: I want to share a Theme context between components that are not wrapped together as children.
// theme_context.jsx
const existingTheme = localStorage.getItem('displayTheme') || 'dark'
export const UserSettings = createContext({
userTheme: existingTheme,
setUserTheme: () => { }
});
export const UserSettingsProvider = ({ children }) => {
const [userTheme, setUserTheme] = useState(existingTheme);
console.log('getDesignTokens passed', children, userTheme)
const muiTheme = createTheme(getDesignTokens(userTheme));
const value = { userTheme, setUserTheme };
return (
<UserSettings.Provider value={value}>
<ThemeProvider theme={muiTheme}>
<CssBaseline />
{children}
</ThemeProvider>
</UserSettings.Provider>
)
}
// Problem: provider context theme is not updated for the footer component when trigger is clicked in navbar component, even though they both import the same context.
// navbar.jsx
import { UserSettingsProvider } from '~/components/theme_context'
ReactDOM.render(
<UserSettingsProvider>
<ResponsiveAppBar />
</UserSettingsProvider>,
document.getElementById('nav-bar')
);
// footer.jsx
import { UserSettingsProvider } from '~/components/theme_context'
ReactDOM.render(
<UserSettingsProvider>
<ResponsiveFooter />
</UserSettingsProvider>,
document.getElementById('footer')
);
// The following works (both children are updated upon theme change trigger) but it means i can only use one dom node, which i do not want.
import { UserSettingsProvider } from '~/components/theme_context'
ReactDOM.render(
<UserSettingsProvider>
<ResponsiveAppBar />
<ResponsiveFooter />
</UserSettingsProvider>,
document.getElementById('root')
);
Is there some way to identify UserSettingsProvider as common for all of its children, without wrapping?
Use Portals, as shown here:
https://stackoverflow.com/a/50024620/9938721
Children are wrapped together in the same context but rendered in different nodes.