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




