Привет, это мой первый пост на Хабр. Надеюсь, Вам будет интересно.
Итак, я хочу начать серию постов, напрямую или косвенно касающихся создания 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, функциональность которого поможет нам визуализировать компоненты на оснавании девайса юзера.
Спасибо.