Использование Context API в React для создания адаптивного дизайна приложения

Привет, данная статья является продолжением вот этого поста, где я решил начать серию небольших учебных пособий по созданию UI-Kit. Там описан метод использования контекста для создания темы приложения. Сегодня я хочу дополнить приложение еще одним контекстом, который поможет нам показывать компоненты UI, основываясь на дивайсе юзера.

image

В данном примере я также буду использовать модуль create-react-context.

Дерево задания будет идентичным с предыдущим. Назовем новую папку media-context.

media-context/    MediaConsumer/       MediaConsumer.js       index.js     MediaProvider/       MediaProvider.js       index.js   constants.js    context.js   index.js 

Быстренько разберемся с index’ами.

media-context/index.js

export { MediaProvider } from './MediaProvider'; export { MediaConsumer } from './MediaConsumer'; 

theme-context/MediaConsumer/index.js

export { MediaConsumer } from './MediaConsumer'; 

theme-context/MediaProvider/index.js

export { MediaProvider } from './MediaProvider'; 

theme-context/context.js
Как и ранее, создаем createContext (модуль нпм).

import createContext from 'create-react-context';  const { Provider, Consumer } = createContext();  export { Provider, Consumer }; 

Импортируем, деструктурируем и экспортируем полученные компоненты.

media-context/constants.js
Переменные сохраним тут.

export const devices = ["mobile", "tablet", "desktop", "native"]; export const defaultDevice = "mobile"; 

В адаптивном подходе юзер в основном использует 4 вида дивайсов — настольный, планшет, мобильный и нативное приложение (native). Другие возможные устройства: смарт-тв, часы и т.п. В данном примере будем использовать только mobile & desktop.

theme-context/MediaProvider/MediaProvider.js
Как мы уже знаем, в React.Context доступен Provider, который «кормит» консюмеров контекстом. Он позволяет им слушать и реагировать на изменения контекста.

Props Провайдераdevice и touchable. Напомню, что все значения переданные в value провайдера станут доступными для консюмеров.

import React from "react"; import PropTypes from "prop-types";  import { Provider } from "../context"; import { devices, defaultDevice } from "../constanst";  function MediaProvider(props) {   const device = devices.includes(props.device)     ? props.device     : props.defaultDevice;   return <Provider value={{ ...props, device }}>{props.children}</Provider>; }  MediaProvider.propTypes = {   device: PropTypes.oneOf(devices),   touchable: false,   children: PropTypes.node };  MediaProvider.defaultProps = {   device: defaultDevice,   touchable: false };  export { MediaProvider }; 

theme-context/MediaConsumer/MediaConsumer.js

Описание функциональности консюмера можно найти в предыдущей статье, но если вкратце, то Consumer реагирует на контекс и возвращает новый компонент.

В данном случае мы передаем два параметра в children: вид дивайса и является ли устройство сенсорным.

import React from "react"; import PropTypes from "prop-types"; import { defaultTo } from "lodash";  import { devices, defaultDevice } from "../constanst"; import { Consumer } from '../context';  function MediaConsumer(props) {   return (     <Consumer>       {media => props.children({         touchable: defaultTo(media.touchable, props.defaultTouchable),         device: defaultTo(media.device, props.defaultDevice),       })}     </Consumer>   ) }  MediaConsumer.propTypes = {   defaultTouchable: PropTypes.bool,   defaultDevice: PropTypes.oneOf(devices),   children: PropTypes.func.isRequired };  MediaConsumer.defaultProps = {   defaultDevice,   defaultTouchable: false };  export { MediaConsumer }; 

Теперь в нашем приложении доступен новый контекст, давайте им воспользуемся.

import React from "react"; import ReactDOM from "react-dom"; import { isMobile } from "react-device-detect"; import cx from "classnames"; import { ThemeConsumer, ThemeProvider } from "./theme-context"; import { MediaConsumer, MediaProvider } from "./media-context";  import "./styles.css";  function renderSVG({ device, touchable }) {   if (device === "mobile" && touchable) {     return "https://image.flaticon.com/icons/svg/124/124114.svg";   }    if (device === "tablet" && touchable) {     return "https://image.flaticon.com/icons/svg/124/124099.svg";   }    if (device === "desktop") {     return "https://image.flaticon.com/icons/svg/124/124092.svg";   } }  function MyComponent() {   const renderMyComponent = (theme, media) => {     const myComponentClassName = cx("my-class", {       "my-class-dark": theme === "dark",       "my-class-light": theme === "light"     });     return (       <div className="wrapperDiv">         <object           className={myComponentClassName}           data={renderSVG(media)}           type="image/svg+xml"         />       </div>     );   };   return (     <MediaConsumer>       {media => (         <ThemeConsumer>           {theme => renderMyComponent(theme, media)}         </ThemeConsumer>       )}     </MediaConsumer>   ); }  function App() {   return (     <MediaProvider       device={isMobile ? "mobile" : "desktop"}       touchable={isMobile}     >       <ThemeProvider theme="light">         <MyComponent />       </ThemeProvider>     </MediaProvider>   ); }  const rootElement = document.getElementById("root"); ReactDOM.render(<App />, rootElement); 

Для использования медиаконтеста нам потребуется медиадетектор (для получения информации о дивайсе юзера). В нашем приложении медиадетектора нет, поэтому возьмем его отсюда — react-device-detect, а именно флаг isMobile.

Как и с контекстной темой, мы обернем наш тестовый компонент в медиапровайдере. Значение пропсов, которые провайдер передаст своему консюмеру, будут зависть от устройства клиента. Зашел с мобильного, посылаем мобильную версию сайта, с компьютера — десктопную. Рабочий код можно посмотреть тут.

Чтобы увидеть разницу, зайдите по ссылке с настольного и мобильного браузера.

Все! Теперь наше приложение имеет два контекста, которые помогут нам создавать более разносторонние и гибкие компоненты в нашем UI-Kit. В следующем посту я попробую создать комплексный компонент с использованием обоих контекстов. Надеюсь, Вы найдете статью полезной.

Спасибо.


ссылка на оригинал статьи https://habr.com/ru/post/463597/

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *