Привет, это мой первый пост на Хабр. Надеюсь, Вам будет интересно.
Итак, я хочу начать серию постов, напрямую или косвенно касающихся создания ui-kit.

Задача данного поста: Найти решение контроля темы приложения, компоненты которого выполнены в
В данном примере я буду использовать модуль
Начнем с создания папки в корне проекта (src/) под названием theme-context. Структура данной папки будет выглядеть следующим образом:
Лично, я всегда начинаю с файла index.js. Делаешь все импорты и экспорты вначале, и потом уже голова о них не болит.
theme-context/index.js
theme-context/ThemeConsumer/index.js
theme-context/ThemeProvider/index.js
theme-context/context.js
Далее, мы создадим контекст при помощи
Импортируем
theme-context/constants.js
Здесь все просто, создаем наши переменные, чтобы не загрязнять основные файлы.
Как я и говорил ранее, у нашего приложения будет две темы — лайт и дарк.
theme-context/ThemeProvider/ThemeProvider.js
Здесь речь пойдет о провайдере — компоненте, который доступен в каждом объекте
В нашем примере, проп
theme-context/ThemeConsumer/ThemeConsumer.js
В данном файле мы будем работать с Consumer — это компонент, который «слушает, ждет» изменения контекста. Дитя (Children) данного компонента — функция. Это обязательное требование при использовании
Данная функция получает значения текущего контекста и возвращает
Из документации: значение аргумента (в нашем случае {theme => /* визуализировать что-либо на основе значения контекста */}) будет равно пропсу
Тут стоит обратить внимание на следующее:
Если тема не была выбрана эксплицитно, нам нужно, чтобы тема компонентов была выбрана автоматически, для этого я использую утиль из
Вот и все, контекст темы готов к использованию!
Давайте рассмотрим, как его применить. Создадим простой компонент, который будет слушать и реагировать на тему контекста нашего приложения.
Итак, мы обернули наш
мы сможем использовать ее при создании компонента
Рабочий код можно посмотреть тут.
Вот и все, надеюсь, Вы найдете данный пост полезным. В следующем посту я попробую создать media-context, функциональность которого поможет нам визуализировать компоненты на оснавании девайса юзера.
Спасибо.
Итак, я хочу начать серию постов, напрямую или косвенно касающихся создания ui-kit.

Задача данного поста: Найти решение контроля темы приложения, компоненты которого выполнены в
React.js. Будем использовать две глобальные темы — dark и light.В данном примере я буду использовать модуль
create-react-context, для создания контекста.Начнем с создания папки в корне проекта (src/) под названием theme-context. Структура данной папки будет выглядеть следующим образом:
theme-context/ ThemeConsumer/ ThemeConsumer.js index.js ThemeProvider/ ThemeProvider.js index.js constants.js context.js index.js
Лично, я всегда начинаю с файла index.js. Делаешь все импорты и экспорты вначале, и потом уже голова о них не болит.
theme-context/index.js
export { ThemeProvider } from './ThemeProvider'; export { ThemeConsumer } from './ThemeConsumer';
theme-context/ThemeConsumer/index.js
export { ThemeConsumer } from './ThemeConsumer';
theme-context/ThemeProvider/index.js
export { ThemeProvider } from './ThemeProvider';
theme-context/context.js
Далее, мы создадим контекст при помощи
createContext (простите за каламбур), используя модуль отсюда.import createContext from 'create-react-context'; const { Provider, Consumer } = createContext(); export { Provider, Consumer };
Импортируем
createContext, деструктурируем его на Provider и Consumer, и экспортируем их.theme-context/constants.js
Здесь все просто, создаем наши переменные, чтобы не загрязнять основные файлы.
export const themeLight = 'light'; export const themeDark = 'dark'; export const defaultTheme = themeLight; export const themes = [themeLight, themeDark];
Как я и говорил ранее, у нашего приложения будет две темы — лайт и дарк.
theme-context/ThemeProvider/ThemeProvider.js
Здесь речь пойдет о провайдере — компоненте, который доступен в каждом объекте
React.Context. Он позволяет консюмерам слушать и реагировать на изменения контекста.В нашем примере, проп
Провайдера — это theme, который будет передан всем Консюмерам-потомкам данного Providerа.import React from 'react'; import { Provider } from '../context'; import { defaultTheme, themes } from '../constants'; function ThemeProvider({ theme, children }) { return <Provider value={theme}>{children}</Provider>; } export { ThemeProvider };
theme-context/ThemeConsumer/ThemeConsumer.js
В данном файле мы будем работать с Consumer — это компонент, который «слушает, ждет» изменения контекста. Дитя (Children) данного компонента — функция. Это обязательное требование при использовании
Consumer.Данная функция получает значения текущего контекста и возвращает
React Node, проще говоря — компонент.Из документации: значение аргумента (в нашем случае {theme => /* визуализировать что-либо на основе значения контекста */}) будет равно пропсу
theme ближайшего, вышестоящего в дереве Provider для данного контекста.import React from 'react'; import { defaultTo } from 'lodash'; import { Consumer } from '../context'; import { defaultTheme, themes } from '../constants'; function ThemeConsumer(props) { return <Consumer>{theme => props.children(defaultTo(theme, props.defaultTheme))}</Consumer>; } export { ThemeConsumer };
Тут стоит обратить внимание на следующее:
Если тема не была выбрана эксплицитно, нам нужно, чтобы тема компонентов была выбрана автоматически, для этого я использую утиль из
lodash — defaultTo. Однако добиться данной функциональности можно множеством иных способов.Вот и все, контекст темы готов к использованию!
Давайте рассмотрим, как его применить. Создадим простой компонент, который будет слушать и реагировать на тему контекста нашего приложения.
.my-class { font-family: sans-serif; text-align: center; font-size: 30px; } .my-class-light { color: #39cccc; } .my-class-dark { color: #001a33; }
import React from "react"; import ReactDOM from "react-dom"; import cx from "classnames"; import { ThemeConsumer, ThemeProvider } from "./theme-context"; import "./styles.css"; function MyComponent() { const renderMyComponent = theme => { const myComponentClassName = cx("my-class", { "my-class-dark": theme === "dark", "my-class-light": theme === "light" }); return ( <div className={myComponentClassName}> <h1>Текст в цвете текущей темы</h1> </div> ); }; return <ThemeConsumer>{theme => renderMyComponent(theme)}</ThemeConsumer>; }; function App() { return ( <MyComponent /> ); } const rootElement = document.getElementById("root"); ReactDOM.render( // поменять текушую тему можно сменив theme на dark <ThemeProvider theme="light"> <App /> </ThemeProvider> , rootElement);
Итак, мы обернули наш
<App /> в провайдере, и теперь тема стала доступна всем компонентам-консюмерам в нашем приложении. Далее, <App /> возвращает <MyComponent />, это Консюмер, и он создаст наш компонент и передаст ему тему нашего приложения. А уже имея тему в виде аргумента:<ThemeConsumer>{theme => renderMyComponent(theme)}</ThemeConsumer>
мы сможем использовать ее при создании компонента
const renderMyComponent = theme => { // создание компонента основываясь на теме };
Рабочий код можно посмотреть тут.
Вот и все, надеюсь, Вы найдете данный пост полезным. В следующем посту я попробую создать media-context, функциональность которого поможет нам визуализировать компоненты на оснавании девайса юзера.
Спасибо.
