Как добавить переключатель темного режима в React

Как добавить переключатель темного режима в React

30 марта 2022 г.

Когда я переделал свой [сайт-портфолио] (https://abbeyperini.dev), я знал, что хочу немного повеселиться с дизайном, и темный и светлый режимы отвечали всем требованиям. Мне понравилось много открытий, которые я сделал во время этого проекта, но больше всего мне нравятся SVG, меняющие цвет. В этом руководстве предполагается, что вы знакомы с React, и я использую v17.0.1 и функциональные компоненты.


Сначала я создал базовый макет. Затем я собрал вместе свои темные и светлые цветовые схемы. Потребовалось немного проб и ошибок, но после тестирования всех моих комбинаций для [достаточного контраста] (https://webaim.org/resources/contrastchecker/) и экспериментов с размещением я обнаружил, что мне нужно 6 переменных CSS. Я думаю, вы могли бы сказать, что я использовал разработку «сначала темная», потому что имена переменных имеют смысл в контексте темной темы. Светлая тема имеет меньше вариаций, но требует --button-border, где --accent будет того же цвета, что и фон.


```javascript


.theme-темный {


--темный текст: #292929;


--light-текст: #F9F8F8;


--темный фон: #2F4550;


--светлый фон: #586F7C;


--акцент: #B8DBD9;


--button-border: #B8DBD9;


```javascript


.theme-свет {


--темный текст: #5E4B56;


--light-текст: #5E4B56;


--темный фон: #DBE7E4;


--light-background: #EDCDD2;


--акцент: #DBE7E4;


--button-border: #5E4B56;


Затем я приступил к применению цветов к моему базовому макету:


```javascript


html, #корень {


цвет фона: var(--темный-фон);


цвет: var(--темный текст);


навигация {


цвет фона: var(--темный-фон);


цвет: var(--light-text);


.основной контейнер {


цвет фона: var(--light-background);


Я также установил фон разделов контента, который я хотел выделить, на --accent. --dark-text работал бы на всех фонах в темной теме, но я установил для заголовков разделов значение --light-text, чтобы они больше выделялись.


Я нашел [учебник по базовому переключению тем] от Musthaq Ahamad (https://medium.com/@haxzie/dark-and-light-theme-switcher-using-css-variables-and-pure-javascript-zocada-dd0059d72fa2) , и приступил к применению его к функциональным компонентам React. Я поместил функции для изменения темы и проверки localStorage для предпочтений темы в файл с именем themes.js.


```javascript


функция setTheme(themeName) {


localStorage.setItem('тема', имятемы);


document.documentElement.className = темаимя;


функция keepTheme () {


если (localStorage.getItem('тема')) {


если (localStorage.getItem('тема') === 'темная тема') {


setTheme('темная тема');


} else if (localStorage.getItem('theme') === 'theme-light') {


setTheme('светлая тема')


} еще {


setTheme('темная тема')


модуль.экспорт = {


установить тему,


держать тему


В моем файле App.js я добавил keepTheme() к моему useEffect().


```javascript


импортировать {keepTheme} из './utils/themes';


приложение функции () {


использоватьЭффект(() => {


сохранить тему();


Затем я добавил компонент-переключатель к своему компоненту панели навигации. Я создал переключатель в соответствии с [учебником Криса Бонгерса] (https://h.daily-dev-tips.com/creating-day-night-css-only-toggle-switch), основанным на [Dribbble Кати Де Хуан] (https ://dribbble.com/shots/3220898-Day-Night-toggle-DailyUI-015). Затем я [отрегулировал размер и переключил его на темный режим по умолчанию] (https://github.com/abbeyperini/Portfolio2.0/blob/master/portfolio/src/styles/toggle.css). Хотя этот переключатель настолько симпатичный, что вы можете умереть, это руководство будет работать с любой <button> или интерактивным <input>. Во-первых, я настроил базовый JSX, локальное состояние и переменную для хранения темы, которую мы получаем из localStorage:


```javascript


импортировать React, {useEffect, useState} из 'реагировать';


импортировать '../styles/toggle.css';


импортировать {setTheme} из '../utils/themes';


функция Переключение () {


const [togClass, setTogClass] = useState('темный');


пусть тема = localStorage.getItem('тема');


вернуть (








переключатель экспорта по умолчанию;


Когда пользователь щелкает переключатель, я хочу, чтобы тема на странице менялась, а переключатель менялся вместе с ней. Я добавил импортированную функцию setTheme() и setTogClass() из локального состояния в функцию handleOnClick. Вы можете видеть, где он передается кликабельной части переключателя в JSX выше.


```javascript


константа handleOnClick = () => {


если (localStorage.getItem('тема') === 'темная тема') {


setTheme('светлая тема');


setTogClass («свет»)


} еще {


setTheme('темная тема');


setTogClass («темный»)


Я использовал useEffect() этого компонента, чтобы убедиться, что togClass локального состояния всегда загружается с правильной темой.


использоватьЭффект(() => {


если (localStorage.getItem('тема') === 'темная тема') {


setTogClass («темный»)


} else if (localStorage.getItem('theme') === 'theme-light') {


setTogClass («свет»)


}, [тема])


Поскольку мой переключатель является флажком, темная тема должна показывать неотмеченное (луна) состояние, а светлая тема должна показывать отмеченное (солнце) состояние. Мне не удалось заставить defaultChecked работать так, как я хотел, поэтому я заменил непроверенный <input> этим условным рендерингом тернарный оператор (условный оператор ):


```javascript


togClass === "свет" ?




Если вы использовали <button>, вы могли бы легко использовать условный рендеринг, подобный этому, чтобы изменить атрибут className в теге <button> и получить тот же эффект.


Собрав все вместе, код компонента-переключателя выглядит так:


```javascript


импортировать React, {useEffect, useState} из 'реагировать';


импортировать '../styles/toggle.css';


импортировать {setTheme} из '../utils/themes';


функция Переключение () {


const [togClass, setTogClass] = useState('темный');


пусть тема = localStorage.getItem('тема');


константа handleOnClick = () => {


если (localStorage.getItem('тема') === 'темная тема') {


setTheme('светлая тема');


setTogClass («свет»)


} еще {


setTheme('темная тема');


setTogClass («темный»)


использоватьЭффект(() => {


если (localStorage.getItem('тема') === 'темная тема') {


setTogClass («темный»)


} else if (localStorage.getItem('theme') === 'theme-light') {


setTogClass («свет»)


}, [тема])


вернуть (



togClass === "свет" ?








Обновлять


Чтобы увидеть, как я реорганизовал логику этого компонента и сделал его доступным, прочитайте Доступный переключатель темного режима в React.


Наконец, моя любимая часть: SVG с переключением цветов! Переменные CSS работают и в коде SVG!


Я получил код SVG для значков Github и Chrome от [DEVICON] (https://devicon.dev/). Для значка Github все, что мне нужно было изменить, это один атрибут заполнения в <g>:


```разметка



Значок Chrome имел атрибут заполнения в <circle> и <path>:


```разметка



Результат выглядит следующим образом: рабочий стол - переключатель выглядит как луна со звездами, щелчок меняет сайт с темного режима на светлый, и переключатель теперь выглядит как солнце с облаками


мобильный телефон - переключатель выглядит как луна со звездами, щелчок меняет сайт с темного режима на светлый, а переключатель теперь выглядит как солнце с облаками


Заключение


Я попытался включить весь соответствующий код, но вы также можете увидеть полный код моего сайта в его [репозитории Github] (https://github.com/abbeyperini/Portfolio2.0). Если вам понравилась эта статья или остались вопросы, пожалуйста, оставьте комментарий! Я также хотел бы увидеть что-нибудь построенное по этому уроку.


Также опубликовано здесь



Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE