Implementarea modului întunecat în aplicațiile React folosind componente cu stil

Publicat: 2022-03-10
Rezumat rapid ↬ Modul Light este o convenție în majoritatea aplicațiilor web și mobile. Cu toate acestea, în dezvoltarea modernă, am văzut cum modul întunecat, care afișează text deschis și elemente de interfață pe un fundal întunecat, devine rapid o preferință a utilizatorului. În acest articol, vom învăța cum să implementăm eficient modul întunecat într-o aplicație React pe o pagină web simplă, folosind biblioteca de componente cu stil și utilizând unele caracteristici React, cum ar fi cârlige. Vom discuta, de asemenea, avantajele și dezavantajele modului întunecat și de ce ar trebui adoptat.

Una dintre caracteristicile software cel mai frecvent solicitate este modul întunecat (sau modul noapte, așa cum îl numesc alții). Vedem modul întunecat în aplicațiile pe care le folosim în fiecare zi. De la aplicații mobile la aplicații web, modul întunecat a devenit vital pentru companiile care doresc să aibă grijă de ochii utilizatorilor lor.

Modul întunecat este o caracteristică suplimentară care afișează în mare parte suprafețe întunecate în interfața de utilizare. Majoritatea companiilor importante (cum ar fi YouTube, Twitter și Netflix) au adoptat modul întunecat în aplicațiile lor mobile și web.

Deși nu vom aprofunda în React și componentele stilate, ar fi utilă cunoștințe de bază despre React, CSS și componentele stilate. Acest tutorial va aduce beneficii celor care doresc să-și îmbunătățească aplicațiile web, oferindu-le celor care iubesc modul întunecat.

StackOverflow anunță modul întunecat pe Twitter
StackOverflow anunță modul întunecat pe Twitter (previzualizare mare)

Cu câteva zile înainte de scrierea acestui articol, StackOverflow a anunțat lansarea modului întunecat, oferind utilizatorilor șansa de a comuta între cele două moduri.

Modul întunecat reduce oboseala ochilor și vă ajută atunci când lucrați o perioadă lungă de timp la un computer sau un telefon mobil.

Ce este modul întunecat?

Modul întunecat este schema de culori a oricărei interfețe care afișează text deschis și elemente de interfață pe un fundal întunecat, ceea ce face ca ecranul să fie puțin mai ușor de privit la telefoane mobile, tablete și computere. Modul întunecat reduce lumina emisă de ecran, menținând în același timp raporturile minime de contrast de culoare necesare pentru lizibilitate.

Mai multe după săritură! Continuați să citiți mai jos ↓

De ce ar trebui să îți pese de modul întunecat?

Modul întunecat îmbunătățește ergonomia vizuală prin reducerea oboselii ochilor, ajustând ecranul la condițiile actuale de lumină și oferind ușurință în utilizare pe timp de noapte sau în medii întunecate.

Înainte de a implementa modul întunecat în aplicația noastră, să ne uităm la beneficiile acestuia.

Economie de baterie

Modul întunecat în aplicațiile web și mobile poate prelungi durata de viață a bateriei unui dispozitiv. Google a confirmat că modul întunecat pe ecranele OLED a fost de mare ajutor pentru durata de viață a bateriei.

De exemplu, la 50% luminozitate, modul întunecat din aplicația YouTube economisește cu aproximativ 15% mai multă energie pe ecran decât un fundal alb plat. La 100% luminozitatea ecranului, interfața întunecată economisește 60% din energia ecranului.

Modul întunecat este frumos

Modul întunecat este frumos și poate spori în mod semnificativ atractivitatea ecranului.

În timp ce majoritatea produselor au acel aspect alb și blând, modul întunecat oferă ceva diferit, care se simte misterios și nou.

De asemenea, oferă oportunități excelente de a prezenta conținut grafic, cum ar fi tablouri de bord, imagini și fotografii într-un mod nou.

Twitter întuneric versus modul luminos
Frumusețea modului întunecat al Twitter față de modul luminos (previzualizare mare)

Acum că știți de ce ar trebui să implementați modul întunecat în următoarea aplicație web, haideți să ne aprofundăm în componentele stilate, care este resursa definitorie a acestui tutorial.

Modul întunecat este schema de culori a oricărei interfețe care afișează text deschis și elemente de interfață pe un fundal întunecat, ceea ce îl face puțin mai ușor de văzut pe telefoanele mobile, tablete și computere.

Ce sunt componentele stilate?

Pe parcursul acestui articol, vom folosi foarte des biblioteca de componente cu stil. Au existat întotdeauna multe moduri de a stila o aplicație web modernă. Există metoda tradițională de stilare la nivel de document, care include crearea unui fișier index.css și legarea acestuia la HTML sau stilarea în interiorul fișierului HTML.

S-au schimbat multe în modul în care aplicațiile web sunt stilate recent, de la introducerea CSS-in-JS.

CSS-in-JS se referă la un model în care CSS este compus folosind JavaScript. Utilizează literale șablon etichetate pentru a stila componentele într-un fișier JavaScript.

Pentru a afla mai multe despre CSS-in-JS, consultați articolul Anna Monus pe acest subiect.

styled-components este o bibliotecă CSS-in-JS care vă permite să utilizați toate caracteristicile CSS pe care le iubiți, inclusiv interogări media, pseudo-selectori și imbricare.

De ce componente stilate?

styled-components a fost creat din următoarele motive:

  • Fără nume de clasă iad
    În loc să vă zgâriați din cap pentru a găsi un nume de clasă pentru un element, styled-components generează nume de clasă unice pentru stilurile dvs. Nu va trebui niciodată să vă faceți griji cu privire la greșeli de ortografie sau la utilizarea numelor de clasă care nu au sens.
  • Folosind recuzită
    componentele cu stil ne permit să extindem proprietățile de stil folosind parametrul props , folosit în mod obișnuit în React - astfel, afectând dinamic senzația unei componente prin starea aplicației.
  • Suporta sintaxa Sass
    Scrierea din cutie a sintaxei Sass fără a fi nevoie să configurați preprocesoare sau instrumente de construcție suplimentare este posibilă cu componentele stilate. În definițiile stilului dvs., puteți utiliza caracterul & pentru a viza componenta curentă, utilizați pseudo-selectori și experimentați imbricarea.
  • Tematică
    Componentele cu stil au suport complet pentru tematică prin exportul unei componente ThemeProvider . Această componentă oferă o temă tuturor componentelor React din interiorul său prin intermediul API-ului Context. În arborele de randare, toate componentele stilizate vor avea acces la tema furnizată, chiar și atunci când au mai multe niveluri adânci. Pe măsură ce continuăm în acest tutorial, ne vom aprofunda caracteristicile tematice ale componentelor stilizate.

Pentru a afla mai multe avantaje ale componentelor stilizate, consultați articolul lui Kris Guzman.

Implementarea modului întunecat

În acest articol, vom implementa modul întunecat pe o pagină web simplă asemănătoare YouTube.

Pentru a continua, asigurați-vă că ați clonat depozitul original din ramura de starter .

Configurare

Să instalăm toate dependențele din fișierul nostru package.json . Din terminal, rulați următoarea comandă:

 npm install

După instalarea cu succes, rulați npm start . Iată cum arată pagina web fără modul întunecat implementat pe ea.

Pagina web care va fi folosită, fără modul întunecat
Pagina web care va fi folosită, fără modul întunecat. (Previzualizare mare)

Pentru a instala styled-components , în terminalul dvs. rulați npm install styled-components .

Implementarea

Pentru a implementa modul întunecat, trebuie să creăm patru componente diferite.

  • Theme
    Acesta conține proprietățile de culoare ale temelor noastre luminoase și întunecate.
  • GlobalStyles
    Acesta conține stilurile globale pentru întregul document.
  • Toggler
    Acesta deține elementul buton care comută funcționalitatea.
  • useDarkMode
    Acest cârlig personalizat gestionează logica din spatele schimbării temei și persistența temei noastre în localStorage.

Componenta Temă

În folderul src , veți vedea componente în folderul components . Creați un fișier Themes.js și adăugați următorul cod la acesta.

 export const lightTheme = { body: '#FFF', text: '#363537', toggleBorder: '#FFF', background: '#363537', } export const darkTheme = { body: '#363537', text: '#FAFAFA', toggleBorder: '#6B8096', background: '#999', }

Aici, am definit și exportat obiecte lightTheme și darkTheme cu variabile de culoare distincte. Simțiți-vă liber să experimentați și să personalizați variabilele potrivite dvs.

Componenta globalStyles

Rămânând în folderul de components , creați un fișier globalStyles.js și adăugați următorul cod:

 import { createGlobalStyle} from "styled-components" export const GlobalStyles = createGlobalStyle` body { background: ${({ theme }) => theme.body}; color: ${({ theme }) => theme.text}; font-family: Tahoma, Helvetica, Arial, Roboto, sans-serif; transition: all 0.50s linear; } `

Am importat createGlobalStyle din componentele cu stil. Metoda createGlobalStyle înlocuiește metoda injectGlobal, acum depreciată, din versiunea 3 a componentelor stilate. Această metodă generează o componentă React, care, atunci când este adăugată în arborele de componente, va injecta stiluri globale în document, în cazul nostru, App.js .

Am definit o componentă GlobalStyle și am atribuit proprietăți de background și color valorilor din obiectul temă. Astfel, de fiecare dată când comutăm comutatorul, valorile se vor schimba în funcție de tema întunecată sau obiectele cu temă luminoasă pe care le transmitem la ThemeProvider (care vor fi create ulterior, pe măsură ce procedăm).

Proprietatea de tranziție de 0.50s permite ca această modificare să aibă loc puțin mai ușor, astfel încât, pe măsură ce comutăm înainte și înapoi, putem vedea schimbările care se întâmplă.

Crearea unei funcționalități de comutare a temei

Pentru a implementa funcționalitatea de comutare a temei, trebuie să adăugăm doar câteva linii de cod. În fișierul App.js , adăugați următorul cod (rețineți că codul evidențiat este ceea ce ar trebui să adăugați):

 import React, { useState, useEffect } from "react";
import {ThemeProvider} from "styled-components"; import { GlobalStyles } from "./components/Globalstyle"; import { lightTheme, darkTheme } from "./components/Themes"
import "./App.css"; import dummyData from "./data"; import CardList from "./components/CardList"; const App = () => { const [videos, setVideos] = useState([]);
 const [theme, setTheme] = useState('light'); const themeToggler = () => { theme === 'light' ? setTheme('dark') : setTheme('light') }
 useEffect(() => { const timer = setTimeout(() => { setVideos(dummyData); }, 1000); return () => clearTimeout(timer); }, []); return (
 <ThemeProvider theme={theme === 'light' ? lightTheme : darkTheme}> <> <GlobalStyles/>
 <div className="App">
 <button onClick={themeToggler}>Switch Theme</button>
 { videos.map((list, index) => { return ( <section key={index}> <h2 className="section-title">{list.section}</h2> <CardList list={list} /> <hr /> </section> ); })} </div>
 </> </ThemeProvider>
); }; export default App;

Codul evidențiat este cel nou adăugat la App.js Am importat ThemeProvider din styled-components . ThemeProvider este o componentă de ajutor din biblioteca de componente cu stil care oferă suport pentru tematică. Această componentă de ajutor injectează o temă în toate componentele React de sub ea însăși prin API-ul Context.

În arborele de randare, toate componentele stilizate vor avea acces la tema furnizată, chiar și atunci când au mai multe niveluri adânci. Consultați secțiunea „Teming”.

Apoi, importăm pachetul ./components/Globalstyle GlobalStyle În cele din urmă, de sus, importăm atât obiectele lightTheme , cât și darkTheme din ./components/Themes .

Pentru a crea o metodă de comutare, avem nevoie de o stare care să mențină valoarea inițială a culorii temei noastre. Deci, creăm o stare de theme și setăm starea inițială la light , folosind cârligul useState .

Acum, pentru funcționalitatea de comutare.

Metoda themeToggler folosește un operator ternar pentru a verifica starea theme și comută între întuneric sau lumină în funcție de valoarea condiției.

ThemeProvider , o componentă de ajutor pentru componente cu stil, include totul în instrucțiunea return și injectează orice componente de sub ea. Amintiți-vă că GlobalStyles injectează stiluri globale în componentele noastre; prin urmare, este numit în interiorul componentei ThemeProvider .

În cele din urmă, am creat un buton cu un eveniment onClick care îi atribuie metoda themeToggler .

Să vedem rezultatul până acum.

Modul întunecat implementat fără persistență.
Modul întunecat implementat fără persistență (previzualizare mare)

Fișierul nostru App.js trebuie refactorizat; o mare parte din codul său nu este USCAT. (DRY înseamnă „nu te repeta”, un principiu de bază al dezvoltării de software menit să reducă repetarea.) Toată logica pare să fie în App.js ; este o bună practică să ne separăm logica de dragul clarității. Deci, vom crea o componentă care se ocupă de funcționalitatea de comutare.

Comutați componentă

Încă în folderul components , creați un fișier Toggler.js și adăugați următorul cod la acesta:

 import React from 'react' import { func, string } from 'prop-types'; import styled from "styled-components" const Button = styled.button` background: ${({ theme }) => theme.background}; border: 2px solid ${({ theme }) => theme.toggleBorder}; color: ${({ theme }) => theme.text}; border-radius: 30px; cursor: pointer; font-size:0.8rem; padding: 0.6rem; } \`; const Toggle = ({theme, toggleTheme }) => { return ( <Button onClick={toggleTheme} > Switch Theme </Button> ); }; Toggle.propTypes = { theme: string.isRequired, toggleTheme: func.isRequired, } export default Toggle;

Pentru a menține lucrurile în ordine, ne-am stilat butonul de comutare în componenta Toggle , folosind funcția de styled din componentele stilate.

Acesta este doar pentru prezentare; puteți modela butonul după cum credeți de cuviință.

În interiorul componentei Toggle , trecem două elemente de recuzită:

  • theme furnizează tema curentă (luminoasă sau întunecată);
  • funcția toggleTheme va fi folosită pentru a comuta între teme.

Apoi, returnăm componenta Button și atribuim o funcție toggleTheme evenimentului onClick .

În cele din urmă, folosim propTypes pentru a ne defini tipurile, asigurându-ne că theme noastră este un string și isRequired , în timp ce toggleTheme este func și isRequired .

Utilizarea cârligelor personalizate ( useDarkMode )

La construirea unei aplicații, scalabilitatea este primordială, ceea ce înseamnă că logica noastră de business trebuie să fie reutilizabilă, astfel încât să o putem folosi în multe locuri și chiar în diferite proiecte.

De aceea, ar fi grozav să mutăm funcționalitatea noastră de comutare într-o componentă separată. Pentru asta, ne-am crea propriul cârlig personalizat.

Să creăm un fișier nou numit useDarkMode.js în folderul components și să ne mutăm logica în acest fișier, cu câteva modificări. Adăugați următorul cod la fișier:

 import { useEffect, useState } from 'react'; export const useDarkMode = () => { const [theme, setTheme] = useState('light'); const setMode = mode => { window.localStorage.setItem('theme', mode) setTheme(mode) }; const themeToggler = () => { theme === 'light' ? setMode('dark') : setMode('light') }; useEffect(() => { const localTheme = window.localStorage.getItem('theme'); localTheme && setTheme(localTheme) }, []); return [theme, themeToggler] };

Am adăugat câteva lucruri aici.

  • setMode
    Folosim localStorage pentru a persista între sesiuni în browser. Deci, dacă un utilizator a ales tema întunecată sau deschisă, asta va primi la următoarea vizită la aplicație sau dacă reîncarcă pagina. Prin urmare, această funcție stabilește starea noastră și transmite theme către localStorage .
  • themeToggler
    Această funcție folosește un operator ternar pentru a verifica starea temei și comută între întuneric sau lumină în funcție de adevărul condiției.
  • useEffect
    Am implementat cârligul useEffect pentru a verifica montarea componentelor. Dacă utilizatorul a selectat anterior o temă, o vom trece la funcția noastră setTheme . La final, vom returna theme noastră, care conține theme aleasă și funcția themeToggler pentru a comuta între moduri.

Cred că veți fi de acord că componenta noastră în modul întunecat arată elegant.

Să mergem la App.js pentru ultimele retușuri.

 import React, { useState, useEffect } from "react"; import {ThemeProvider} from "styled-components";
import {useDarkMode} from "./components/useDarkMode"
import { GlobalStyles } from "./components/Globalstyle"; import { lightTheme, darkTheme } from "./components/Themes" import Toggle from "./components/Toggler" import "./App.css"; import dummyData from "./data"; import CardList from "./components/CardList"; const App = () => { const [videos, setVideos] = useState([]);
 const [theme, themeToggler] = useDarkMode(); const themeMode = theme === 'light' ? lightTheme : darkTheme;
useEffect(() => { const timer = setTimeout(() => { setVideos(dummyData); }, 1000); return () => clearTimeout(timer); }, []); return (
 <ThemeProvider theme={themeMode}>
 <> <GlobalStyles/> <div className="App">
 <Toggle theme={theme} toggleTheme={themeToggler} />
 { videos.map((list, index) => { return ( <section key={index}> <h2 className="section-title">{list.section}</h2> <CardList list={list} /> <hr /> </section> ); })} </div> </> </ThemeProvider> ); }; export default App;

Codul evidențiat este nou adăugat în App.js .

În primul rând, importăm cârligul nostru personalizat, destructuram theme și elementele de recuzită themeToggler și le setăm cu funcția useDarkMode .

Rețineți că metoda useDarkMode înlocuiește starea theme noastre, care era inițial în App.js .

Declarăm o variabilă themeMode , care redă fie o temă deschisă, fie o temă întunecată, în funcție de starea modului theme la momentul respectiv.

Acum, componenta noastră de înfășurare ThemeProvider este atribuită variabilei themeMode recent creată themeMode theme .

Și, în sfârșit, în locul butonului obișnuit, trecem componenta Toggle .

Amintiți-vă că, în componenta noastră Toggle , am definit și stilat un buton și le-am transmis atât theme , cât și toggleTheme ca elemente de recuzită. Deci, tot ce trebuie să facem este să transmitem aceste elemente de recuzită în mod corespunzător la componenta Toggle , care va acționa ca butonul nostru în App.js

Da! Modul nostru întunecat este setat și persistă, fără a-și schimba culoarea atunci când pagina este reîmprospătată sau vizitată într-o filă nouă.

Să vedem rezultatul în acțiune:

Modul întunecat implementat, dar cu o eroare în culoarea butonului când browserul se reîncarcă.
Modul întunecat implementat, dar cu o eroare în culoarea butonului când browserul se reîncarcă. (Previzualizare mare)

Aproape totul funcționează bine, dar există un lucru mic pe care îl putem face pentru a ne face experiența splendidă. Comutați la tema întunecată și apoi reîncărcați pagina. Vedeți că culoarea albastră a butonului se încarcă înainte de gri pentru un scurt moment? Acest lucru se întâmplă deoarece cârligul nostru useState inițiază inițial tema light . După aceea, useEffect rulează, verifică localStorage și abia apoi setează theme la dark . Să trecem la cârligul nostru personalizat useDarkMode.js și să adăugăm un mic cod:

 import { useEffect, useState } from 'react'; export const useDarkMode = () => { const [theme, setTheme] = useState('light');
 const [mountedComponent, setMountedComponent] = useState(false)
 const setMode = mode => { window.localStorage.setItem('theme', mode) setTheme(mode) }; const themeToggler = () => { theme === 'light' ? setMode('dark') : setMode('light') }; useEffect(() => { const localTheme = window.localStorage.getItem('theme'); localTheme ? setTheme(localTheme) : setMode('light')
 setMountedComponent(true)
 }, []); return [theme, themeToggler, }, []); return [theme, themeToggler, mountedComponent ]
};

Codul evidențiat este singurul adăugat la useDarkMode.js . Am creat o altă stare numită mountedComponent și am setat valoarea implicită la false folosind hook-ul useState . Apoi, în interiorul cârligului useEffect , setăm starea mountedComponent la true folosind setMountedComponent . În cele din urmă, în matricea de return , includem starea mountedComponent .

În cele din urmă, să adăugăm un pic de cod în App.js pentru ca totul să funcționeze.

 import React, { useState, useEffect } from "react"; import {ThemeProvider} from "styled-components"; import {useDarkMode} from "./components/useDarkMode" import { GlobalStyles } from "./components/Globalstyle"; import { lightTheme, darkTheme } from "./components/Themes" import Toggle from "./components/Toggler" import "./App.css"; import dummyData from "./data"; import CardList from "./components/CardList"; const App = () => { const [videos, setVideos] = useState([]);
 const [theme, themeToggler, mountedComponent] = useDarkMode();
 const themeMode = theme === 'light' ? lightTheme : darkTheme; useEffect(() => { const timer = setTimeout(() => { setVideos(dummyData); }, 1000); return () => clearTimeout(timer); }, []);
 if(!mountedComponent) return <div/>
 return ( <ThemeProvider theme={themeMode}> <> <GlobalStyles/> <div className="App"> <Toggle theme={theme} toggleTheme={themeToggler} /> { videos.map((list, index) => { return ( <section key={index}> <h2 className="section-title">{list.section}</h2> <CardList list={list} /> <hr /> </section> ); })} </div> </> </ThemeProvider> ); }; export default App;

Am adăugat starea noastră mountedComponent ca suport în cârligul useDarkMode și am verificat dacă componenta noastră a fost montată, deoarece asta se întâmplă în cârligul useEffect . Dacă nu s-a întâmplat încă, atunci vom reda un div gol.

Să vedem rezultatul paginii noastre web în modul întunecat.

Rezultatul final al modului întunecat
Rezultatul final al modului întunecat (previzualizare mare)

Acum, veți observa că în modul întunecat, când pagina se reîncarcă, culoarea butonului nu se schimbă.

Concluzie

Modul întunecat devine din ce în ce mai mult o preferință a utilizatorului, iar implementarea lui într-o aplicație web React este mult mai ușoară atunci când utilizați pachetul de tematică ThemeProvider în componentele stilate. Continuați și experimentați cu componente cu stil în timp ce implementați modul întunecat; ai putea adauga pictograme in loc de buton.

Vă rugăm să împărtășiți feedback-ul și experiența dvs. cu funcția de tematică din componentele cu stil în secțiunea de comentarii de mai jos. Mi-ar plăcea să văd cu ce ai venit!

Depozitul de suport pentru acest articol este disponibil pe GitHub. De asemenea, verificați-l pe CodeSandbox.

Referințe

  • „Documentare”, componente stilizate
  • „Creați un mod întunecat al aplicației dvs. folosind Componente stilate”, Tom Nolan, Medium