React и React Native помогают сблизить веб- и мобильную разработку, улучшая опыт как пользователей, так и разработчиков.
Некоторые продвинутые команды уже создают полноценную кроссплатформенную систему проектирования с помощью React и React Native (видеоурок).
Хотя React и RN требуют различной реализации (браузеры и мобильные устройства не одинаковы), типы приложений и компонентов зачастую имеют общий код, бизнес-логику, хуки, реквизиты и даже дизайн-токены.
В данном руководстве будет показано, как превратить общие элементы в общие зависимости для приложений React и RN. Эти компоненты версионируются, так что впоследствии их можно обновлять и управлять ими на разных платформах.
Весь описанный ниже процесс будет упрощен благодаря использованию проекта Bit с открытым исходным кодом.
Здесь можно найти (и использовать) все компоненты из этого руководства.
Итак, погрузимся в процесс.
1. Два компонента: React и React Native
Нам предстоит работа с двумя аккордеонами — одним для React, другим для React Native.
Вот компонент аккордеона React.
Изучите и установите/откройте его, чтобы протестировать локально или отредактировать.
Другой компонент — React Native.
Уделите пару секунд изучению графа “зависимости” каждого компонента. Согласитесь, у них много общих зависимостей.
2. Превращение общего кода в общие зависимости
Наша задача — сделать так, чтобы каждый аккордеон содержал минимум платформенно-ориентированного кода (поскольку API у них разные), и передать все общие части.
С помощью Bit можно что угодно превратить в компоненты, в том числе зависимости компонентов аккордеонов. Поскольку нам нужно максимально увеличить объем кода вне платформенно-ориентированных реализаций, хуки, типы, темы и дизайн-токены будут частью различных компонентов.
Вот зависимости компонентов, которые нужно создать и скомпоновать с аккордеонами React и React Native (можно найти их все здесь):
share-react-react-native --> scope
├── api --> namespace
│ ├── accordion --> component
│ └── accordion-items --> component
├── design-tokens --> namespace
│ ├── base-tokens --> component
│ ├── react-tokens --> component
│ └── rnative-tokens --> component
├── base-ui --> namespace
│ ├── hooks --> namespace
│ │ ├── use-open --> component
│ │ └── use-select --> component
│ ├── react --> namespace
│ │ └── accordion --> component
│ └── react-native --> namespace
│ └── accordion --> component
└── theme --> namespace
├── web --> component
└── mobile --> component
3. Добавление зависимостей в платформенно-ориентированные компоненты
Между React и React Native есть различия. Например, они не допускают применения одинаковых свойств и типов стилей. Если все размерности в React Native не имеют единиц измерения, то в React можно использовать px, rem, em и т.д.
Для выполнения нашей задачи понадобятся базовый объект с наиболее общими значениями и платформенно-ориентированные компоненты с дополнительными свойствами.
Воспользуемся полезным шаблоном создания контекста и хука для внедрения токенов в компоненты. Чтобы заставить их работать с React и React Native, прибегнем к хитрости. Она заключается в том, что у нас будет три вида токенов.
- Базовый токен — общий для обоих:
export interface BaseTokensProps { primaryColor: string; secondaryColor: string; borderColor: string; borderStyle: "solid" | "dotted" | "dashed" | undefined; } export const baseTokens: BaseTokensProps = { primaryColor: "red", secondaryColor: "blue", borderColor: "green", borderStyle: "solid", };
- Токен, дополняющий базовый для использования с React:
import { baseTokens } from "@learnbit-react/web-mobile-design-system.design-tokens.base-tokens"; import type { BaseTokensProps } from "@learnbit-react/web-mobile-design-system.design-tokens.base-tokens"; export interface ReactTokensProps extends BaseTokensProps { spacing: string; fontSize: string; borderWidth: string; } export const reactTokens: ReactTokensProps = { ...baseTokens, spacing: "15px", fontSize: "18px", borderWidth: "3px", };
- Токен, дополняющий базовый для использования с React Native:
import { baseTokens } from "@learnbit-react/web-mobile-design-system.design-tokens.base-tokens"; import type { BaseTokensProps } from "@learnbit-react/web-mobile-design-system.design-tokens.base-tokens"; export interface RNativeTokensProps extends BaseTokensProps { spacing: number; fontSize: number; borderWidth: number; } export const rNativeTokens: RNativeTokensProps = { ...baseTokens, primaryColor: "purple", secondaryColor: "gray", spacing: 10, fontSize: 12, borderWidth: 3, };
Если в вашей среде разработки выполняется автозаполнение местоположения посредством относительного импорта, можете быстро исправить это, выполнив команду
bit link — rewire
.
4. Предоставление тем для React и React Native
В Bit тема может быть и компонентом, что позволяет легко составлять зависимости для дизайн-токенов и тем.
Для нашей темы используем уже имеющийся компонент, который создает тему из объекта. Для этого нужно установить его в рабочее пространство:
$ bit install @teambit/base-react.theme.theme-provider
Нам понадобится объект tan
со свойствами темы. Вызовем функцию createTheme
, указав ее в качестве аргумента. Результатом будет объект с хуком для использования этих значений и компонент, который осуществляет ввод с помощью React Context.
- Вот тема для React:
import { createTheme } from "@teambit/base-react.theme.theme-provider"; import { reactTokens } from "@learnbit-react/web-mobile-design-system.design-tokens.react-tokens"; import type { ReactTokensProps } from "@learnbit-react/web-mobile-design-system.design-tokens.react-tokens"; const theme = createTheme<ReactTokensProps>({ theme: reactTokens, }); const { useTheme, ThemeProvider } = theme; export { useTheme, ThemeProvider };
- А вот и тема для React Native. Передадим опцию
withoutCssVars: true
, чтобы избежать необходимости рендеринга<div>
.
import { createTheme } from "@teambit/base-react.theme.theme-provider"; import { rNativeTokens } from "@learnbit-react/web-mobile-design-system.design-tokens.rnative-tokens"; import type { RNativeTokensProps } from "@learnbit-react/web-mobile-design-system.design-tokens.rnative-tokens"; const theme = createTheme<RNativeTokensProps>({ theme: rNativeTokens, withoutCssVars: true, }); const { useTheme, ThemeProvider } = theme; export { useTheme, ThemeProvider };
Предоставим темы аккордеонам. Теперь это просто сделать: можно импортировать компоненты-темы.
Оба аккордеона будут иметь одинаковый каркас, где мы используем хуки и получаем в качестве возврата соответствующий список, как показано в этом фрагменте:
import { useTheme } from '@learnbit-react/web-mobile-design-system.theme.web // or .mobile in the react-native one! import { useOpen } from '@learnbit-react/web-mobile-design-system.hooks.use-open'; import { useSelect } from '@learnbit-react/web-mobile-design-system.hooks.use-select'; import type { AccordionProps } from '@learnbit-react/web-mobile-design-system.api.accordion'; const GenericAccordionTemplate = ({ elementList } : AccordionProps) => { const { isOpen, toggleOpen } = useOpen(); const { selectedId, setSelection } = useSelect(); const {someValueToken, someValueToken} = useTheme(); return <div_or_View style={{someProp: someValueToken}}>My styled element<div_or_View/>; };
Обратите внимание, что аккордеоны не используют один и тот же хук
useTheme
. Каждый из них использует свой хук в соответствии с заданными типами стилей.
5. Создание веб- и мобильного приложений с общими зависимостями
Наконец пришло время создать веб- и мобильное приложения с использованием новых компонентов и общих зависимостей. В компонуемых приложениях (т.е. с Bit) всегда есть возможность добавить компонент и развернуть его. Поскольку здесь все является компонентом, можно добавить компонент для развертывания в Netlify или создать/добавить любые аналогичные компоненты для развертывания в любом месте. Подробнее здесь.
Веб-приложение React
Вот конечный резульат развертывания в Netlify. Посмотрим, как это сделать.
Создадим компонент приложения и установим Netlify.
$ bit create react-app apps/react/accordion — scope learnbit-react.web-mobile-design-system bit install react-router-dom bit use learnbit-react.web-mobile-design-system/apps/react/accordion bit install @teambit/cloud-providers.deployers.netlify
Теперь добавим аккордеон в код приложения.
import React from "react";
import { Routes, Route } from "react-router-dom";
import { Accordion } from "@learnbit-react/web-mobile-design-system.base-ui.react.accordion";
import { Item } from "@learnbit-react/web-mobile-design-system.api.accordion"; export function AccordionApp() {
return (
<>
{/* header component */}
<Routes>
<Route
path="/"
element={
<Accordion
elementList={[
new Item("Asia", "01").toObject(),
new Item("Africa", "02").toObject(),
new Item("North America", "03").toObject(),
new Item("South America", "04").toObject(),
new Item("Antarctica", "05").toObject(),
new Item("Australia / Oceania", "06").toObject(),
new Item("Europe", "07").toObject(),
]}
/>
}
/>
<Route path="/about">{/* about page component */}</Route>
</Routes>
{/* footer component */}
</>
);
}
Путем настройки приложения в accordion.react-app.ts
и запуска bit tag
, получим его снапшот и развернем его:
bit tag apps/react/accordion -m “First deploy”
Наконец оно развернуто!
Использование компонента React Native в Expo
expo init my-new-project cd my-new-project yarn install @learnbit-react/web-mobile-design-system.base-ui.react-native.accordion @learnbit-react/web-mobile-design-system.api.accordion
Добавим компонент в файл app.js
:
import {Accordion} from '@learnbit-react/web-mobile-design-system.base-ui.react-native.accordion'; import { Item } from '@learnbit-react/web-mobile-design-system.api.accordion'; import {(StyleSheet, View)} from 'react-native'; export default function App() { return ( <View style={styles.container}> <Accordion elementList={[ new Item('Asia', '01').toObject(), new Item('Africa', '02').toObject(), new Item('North America', '03').toObject(), new Item('South America', '04').toObject(), new Item('Antarctica', '05').toObject(), new Item('Australia / Oceania', '06').toObject(), new Item('Europe', '07').toObject(), ]} /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'flex-start', marginTop: 50, }, });
Вот исходный код на GitHub.
Вывод
Браузеры и мобильные устройства отличаются друг от друга, и вы не можете использовать все то общее, что у них есть. При этом у них могут быть общими множество элементов кода и дизайна. Превращение этих элементов в компонуемые зависимости позволит эффективно использовать их совместно, вводя в состав компонентов и приложений React и React Native. Вы сможете версионировать и управлять обновлениями между ними, чтобы сохранить единство кодовой базы и UI/UX на разных платформах.
Читайте также:
- Создание компонента Timer с React и Bit
- Детальное исследование 3 подводных камней React, с которыми сталкиваются разработчики
- 5 лучших курсов по React Native для разработчиков мобильных приложений
Читайте нас в Telegram, VK и Дзен
Перевод статьи Jonathan Saring: Sharing Code Between React and React Native