Dynamic theme in stylized components.

I use stylized components in my React application and want to use a dynamic theme. In some areas he will use my dark theme, some will use light. Since stylized components must be declared outside the component in which they are used, how can we dynamically traverse the theme?

+8
source share
2 answers

This is what ThemeProvider for!

Your stylized components have access to special theme support when they interpolate a function:

 const Button = styled.button` background: ${props => props.theme.primary}; ` 

This <Button /> component will now dynamically respond to a theme defined by ThemeProvider . How do you define a topic? Pass any object to theme prop ThemeProvider :

 const theme = { primary: 'palevioletred', }; <ThemeProvider theme={theme}> <Button>I'm now palevioletred!</Button> </ThemeProvider> 

We provide a theme for your styled components through context , that is, regardless of how many nodes or DOM nodes are between the component and ThemeProvider, it will work in exactly the same way:

 const theme = { primary: 'palevioletred', }; <ThemeProvider theme={theme}> <div> <SidebarContainer> <Sidebar> <Button>I'm still palevioletred!</Button> </Sidebar> </SidebarContainer> </div> </ThemeProvider> 

This means that you can wrap your entire application in one ThemeProvider , and all your stylized components will get this theme. You can dynamically change this property to change between a dark and dark theme!

Your application can have as many or less ThemeProvider as you want. In most applications, you only need one to wrap the entire application, but for part of your application to be light and some other part of the dark theme, you would simply ThemeProvider them in two ThemeProvider , which have different themes:

 const darkTheme = { primary: 'black', }; const lightTheme = { primary: 'white', }; <div> <ThemeProvider theme={lightTheme}> <Main /> </ThemeProvider> <ThemeProvider theme={darkTheme}> <Sidebar /> </ThemeProvider> </div> 

Any style anywhere inside the Main will now be light, and any style anywhere inside the Sidebar will be dark. They adapt depending on what area of ​​the application they are in, and you do not need to do anything to make this happen! πŸŽ‰

I recommend that you familiarize yourself with our topic documents , as stylized components were built with this in mind.

One of the big pain points of styles in JS before stylized components existed was that previous libraries did very well encapsulating and layout styles, but none of them had the proper support. If you want to know more about other aspects of the pain that we had with existing libraries, I would advise you to watch my conversation in ReactNL , where I released stylized text, components. (note: the first appearance of stylized components is ~ 25 minutes, do not be surprised!)

+32
source

Although initially this question concerned the simultaneous launch of several topics, I personally wanted to dynamically switch at runtime one separate topic for the entire application.

Here's how I got it: (here I will use TypeScript and hooks. For simple JavaScript, just delete type s, as and interface ):

I also included all imports at the top of each block code just in case.

We define our theme.ts file

 //theme.ts export const lightTheme = { all: { borderRadius: '0.5rem', }, main: { color: '#FAFAFA', textColor: '#212121', bodyColor: '#FFF', }, secondary: { color: '#757575', }, }; // Force both themes to be consistent! export const darkTheme: Theme = { // Make properties the same on both! all: { ...lightTheme.all }, main: { color: '#212121', textColor: '#FAFAFA', bodyColor: '#424242', }, secondary: { color: '#616161', }, }; export type Theme = typeof lightTheme; export const styled = baseStyled as ThemedStyledInterface<Theme>; 

Then in our master record, in this case App.tsx we define <ThemeProvider> before each component that will use the theme.

 // app.tsx import React, { memo, Suspense, lazy, useState } from 'react'; import { Router } from '@reach/router'; // The header component that switches the styles. import Header from './components/header'; // Personal component import { Loading } from './components'; import { ThemeProvider } from 'styled-components'; // Bring either the lightTheme, or darkTheme, whichever you want to make the default import { lightTheme } from './components/styles/theme'; // Own code. const Home = lazy(() => import('./views/home')); const BestSeller = lazy(() => import('./views/best-seller')); /** * Where the React APP main layout resides: */ function App() { // Here we set the default theme of the app. In this case, // we are setting the lightTheme. If you want the dark, import the 'darkTheme' object. const [theme, setTheme] = useState(lightTheme); return ( <Suspense fallback={<Loading />}> <ThemeProvider theme={theme}> <React.Fragment> {/* We pass the setTheme function (lift state up) to the Header */} <Header setTheme={setTheme} /> <Router> <Home path="/" /> <BestSeller path="/:listNameEncoded" /> </Router> </React.Fragment> </ThemeProvider> </Suspense> ); } export default memo(App); 

And in header.tsx we pass setTheme to the component (raising state):

 // app.tsx import React, { memo, useState } from 'react'; import styled, { ThemedStyledInterface } from 'styled-components'; import { Theme, lightTheme, darkTheme } from '../styles/theme'; // We have nice autocomplete functionality const Nav = styled.nav' background-color: ${props => props.theme.colors.primary}; '; // We define the props that will receive the setTheme type HeaderProps = { setTheme: React.Dispatch<React.SetStateAction<Theme>>; }; function Header(props: function setLightTheme() { props.setTheme(lightTheme); } function setDarkTheme() { props.setTheme(darkTheme); } // We then set the light or dark theme according to what we want. return ( <Nav> <h1>Book App</h1> <button onClick={setLightTheme}>Light </button> <button onClick={setDarkTheme}> Dark </button> </Nav> ); } export default memo(Header); 
0
source

Source: https://habr.com/ru/post/1265452/


All Articles