В ходе разработки мобильных приложений на React Native я перепробовал несколько стандартных библиотек для навигации, но при использовании каждой из них я испытывал просто ужасную, адскую боль. Они были сделаны настолько неудобно и неочевидно, что разработка даже простейших казалось бы фич, превращалась в незаурядный квест.
Используя react-navigation или react-native-router-flux если вам нужно сделать экран, на который можно попасть из нескольких разных мест, вам будет очень трудно составить иерархию вложенных роутов так, чтобы все работало как надо. Или если вам нужно, чтобы какой-нибудь экран появлялся с недефолтной анимацией, то тоже придется попыхтеть. Также этих библиотеках воплощена вредная и деструктивная идея включения туда UI-компонентов вроде верхней полоски навигации и табов. Это прямое нарушение unix-way подхода, когда одна библиотека выполняет одну и только одну функцию, но качественно. Из-за такой тесной связи UI-компонентов с навигацией очень часто возникают баги — на экране появляется несколько полосок навигации, на одной из которых может быть кнопка «назад», а на другой название экрана.
Вдоволь нахлебавшись горя с стандартными библиотеками, я решил разработать свой навигатор. Основными целями при разработке были простота API, отсутствие жесткой структуры вложенности экранов и отделение анимаций от содержимого. Так появился на свет react-native-easy-router.
В тех навигаторах, что я использовал ранее, передаваемые в экран параметры можно было достать только по сложному пути вроде `router.state.params.name`. В моем же навигаторе я передаю параметры напрямую в компонент экрана. В некоторых случаях это может привести к конфликту имен, но решением этой проблемы я решил пренебречь. Также в коде ниже можно увидеть, что у роутов нету четкой структуры и вы можете добавить любой новый экран из любого другого экрана.
С анимацией работать еще проще. Если в react-navigation и react-native-router-flux нужно было извернуться, чтобы сделать какому-то конкретному экрану недефолтную анимацию, то в react-native-easy-router экран может влетать с разными анимациями, и более того, экран может влетать и вылетать с разными анимациями. Например, в нижеприведенном примере экран будет влетать снизу, а улетать направо.
Можно даже добавлять свои собственные кастомные анимации. Может вы хотите, чтобы экран вылетал из правого нижнего угла и кувыркался при этом. Пример того как это сделать можно найти тут.
Разработанный навигатор уже используется в нескольких наших коммерческих проектах, и получил небольшое распространение и теплые отзывы среди некоторых React Native разработчиков. Если вы хотите посмотреть больше примеров использования и решить можно ли использовать данный навигатор в вашем проекте, то можете порыться в репозитории проекта.
Используя react-navigation или react-native-router-flux если вам нужно сделать экран, на который можно попасть из нескольких разных мест, вам будет очень трудно составить иерархию вложенных роутов так, чтобы все работало как надо. Или если вам нужно, чтобы какой-нибудь экран появлялся с недефолтной анимацией, то тоже придется попыхтеть. Также этих библиотеках воплощена вредная и деструктивная идея включения туда UI-компонентов вроде верхней полоски навигации и табов. Это прямое нарушение unix-way подхода, когда одна библиотека выполняет одну и только одну функцию, но качественно. Из-за такой тесной связи UI-компонентов с навигацией очень часто возникают баги — на экране появляется несколько полосок навигации, на одной из которых может быть кнопка «назад», а на другой название экрана.
Вдоволь нахлебавшись горя с стандартными библиотеками, я решил разработать свой навигатор. Основными целями при разработке были простота API, отсутствие жесткой структуры вложенности экранов и отделение анимаций от содержимого. Так появился на свет react-native-easy-router.
Простота API и отсутствие жесткой структуры
В тех навигаторах, что я использовал ранее, передаваемые в экран параметры можно было достать только по сложному пути вроде `router.state.params.name`. В моем же навигаторе я передаю параметры напрямую в компонент экрана. В некоторых случаях это может привести к конфликту имен, но решением этой проблемы я решил пренебречь. Также в коде ниже можно увидеть, что у роутов нету четкой структуры и вы можете добавить любой новый экран из любого другого экрана.
import React from 'react'
import Router from 'react-native-easy-router'
import { Text, View } from 'react-native'
const First = ({ router }) => (
<View style={{ backgroundColor: 'white', flex: 1 }}>
<Text>First screen</Text>
<Text onPress={() => router.push.Second({ name: 'John' })}>Go forward</Text>
</View>
)
const Second = ({ router, name }) => (
<View style={{ backgroundColor: 'pink', flex: 1 }}>
<Text>Second screen</Text>
<Text>Hello {name}!</Text>
<Text onPress={() => router.pop()}>Go back</Text>
</View>
)
const routes = { First, Second }
export default () => <Router routes={routes} initialRoute="First" />
Анимации
С анимацией работать еще проще. Если в react-navigation и react-native-router-flux нужно было извернуться, чтобы сделать какому-то конкретному экрану недефолтную анимацию, то в react-native-easy-router экран может влетать с разными анимациями, и более того, экран может влетать и вылетать с разными анимациями. Например, в нижеприведенном примере экран будет влетать снизу, а улетать направо.
import React from 'react'
import Router from 'react-native-easy-router'
import { Text, View } from 'react-native'
const First = ({ router }) => (
<View style={{ backgroundColor: 'white', flex: 1 }}>
<Text>First screen</Text>
<Text onPress={() => router.push.Second({}, {type:'bottom'})}>Go to second screen</Text>
</View>
)
const Second = ({ router }) => (
<View style={{ backgroundColor: 'pink', flex: 1 }}>
<Text>Second screen</Text>
<Text onPress={() => router.pop({type:'right'})}>Go back</Text>
</View>
)
export default () => <Router routes={{ Screen1, Screen2 }} initialRoute="Screen1" />
Можно даже добавлять свои собственные кастомные анимации. Может вы хотите, чтобы экран вылетал из правого нижнего угла и кувыркался при этом. Пример того как это сделать можно найти тут.
Заключение
Разработанный навигатор уже используется в нескольких наших коммерческих проектах, и получил небольшое распространение и теплые отзывы среди некоторых React Native разработчиков. Если вы хотите посмотреть больше примеров использования и решить можно ли использовать данный навигатор в вашем проекте, то можете порыться в репозитории проекта.