J'utilise des composants stylisés dans mon application React et je souhaite utiliser un thème dynamique. Certaines zones utiliseront mon thème sombre, d'autres utiliseront la lumière. Parce que les composants stylisés doivent être déclarés en dehors du composant dans lequel ils sont utilisés, comment passer dynamiquement à travers un thème?
C'est exactement à cela que sert le composant ThemeProvider
!
Vos composants stylisés ont accès à un accessoire spécial theme
lorsqu'ils interpolent une fonction:
const Button = styled.button`
background: ${props => props.theme.primary};
`
Ce <Button />
le composant répondra maintenant dynamiquement à un thème défini par un ThemeProvider
. Comment définissez-vous un thème? Passez n'importe quel objet au theme
prop du ThemeProvider
:
const theme = {
primary: 'palevioletred',
};
<ThemeProvider theme={theme}>
<Button>I'm now palevioletred!</Button>
</ThemeProvider>
Nous fournissons le thème à vos composants stylisés via context
, ce qui signifie que peu importe le nombre de composants ou de nœuds DOM entre le composant et le ThemeProvider, il fonctionnera toujours exactement de la même manière:
const theme = {
primary: 'palevioletred',
};
<ThemeProvider theme={theme}>
<div>
<SidebarContainer>
<Sidebar>
<Button>I'm still palevioletred!</Button>
</Sidebar>
</SidebarContainer>
</div>
</ThemeProvider>
Cela signifie que vous pouvez envelopper votre application entière dans un seul ThemeProvider
, et tous vos composants stylés obtiendront ce thème. Vous pouvez échanger cette propriété dynamiquement pour basculer entre un thème clair et un thème sombre!
Vous pouvez avoir autant ou autant de ThemeProvider
s dans votre application que vous le souhaitez. La plupart des applications n'auront besoin que d'une seule pour envelopper l'application entière, mais pour qu'une partie de votre application soit à thème clair et une autre partie à thème sombre, vous devez simplement les envelopper dans deux ThemeProvider
s qui ont des thèmes différents:
const darkTheme = {
primary: 'black',
};
const lightTheme = {
primary: 'white',
};
<div>
<ThemeProvider theme={lightTheme}>
<Main />
</ThemeProvider>
<ThemeProvider theme={darkTheme}>
<Sidebar />
</ThemeProvider>
</div>
Tout composant de style n'importe où à l'intérieur de Main
sera désormais à thème clair, et tout composant de style à l'intérieur de Sidebar
sera à thème sombre. Ils s'adaptent en fonction de la zone de l'application dans laquelle ils sont rendus, et vous n'avez rien à faire pour y arriver! ????
Je vous encourage à consulter nos documentation sur le thème , car les composants de style ont été construits dans cet esprit.
L'un des gros points faibles des styles dans JS avant que les composants de style n'existent était que les bibliothèques précédentes encapsulaient et colocalisaient très bien les styles, mais aucune d'entre elles n'avait un support de thème approprié. Si vous voulez en savoir plus sur les autres problèmes rencontrés avec les bibliothèques existantes, je vous encourage à regarder mon exposé à ReactNL où j'ai publié des composants de style. (Remarque: la première apparition des composants stylisés est à ~ 25 minutes, ne soyez pas surpris!)
Bien que cette question soit à l'origine pour avoir plusieurs thèmes en cours d'exécution en même temps, je voulais personnellement basculer dynamiquement à l'exécution un thème unique pour toute l'application.
Voici comment je l'ai réalisé: (J'utiliserai TypeScript et des crochets ici. Pour du JavaScript simple, supprimez simplement les type
s, as
et interface
):
J'ai également inclus toutes les importations en haut de chaque code de bloc au cas où.
Nous définissons notre theme.ts
fichier
//theme.ts
import baseStyled, { ThemedStyledInterface } from 'styled-components';
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>;
Ensuite, dans notre entrée principale, dans ce cas App.tsx
on définit le <ThemeProvider>
avant chaque composant qui va utiliser le thème.
// 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);
Et dans header.tsx nous passons le setTheme au composant (Levée de l'état):
// 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);