React Native: путь новичка
"Если долго сидеть на берегу реки,
можно увидеть,
как проплывает труп фреймворка,
который вы давно хотели изучить."
Китайская народная мудрость
Краткое содержание статьи:
1. Источники информации
2. React модули
3. React Native модули
4. JavaScript библиотеки
5. "Баги"
6. Выводы
React Native - самая, пожалуй, интересная и быстроразвивающаяся платформа. Сегодня ты создаешь новый проект на базе её последней версии, и уже через несколько месяцев она успевает устареть на несколько релизов. И если ещё год назад React Native был еще достаточно сырым продуктом, то уже сейчас к нем написано множество как плагинов для работы с нативными компонентами, так и обычных react-компонент.
Итак, с чего начать?
Могу порекомендовать книгу "Learning React Native: Building Native Mobile Apps with JavaScript" Bonnie Eisenman. Несмотря на то, что примеры из книги написаны с использованием устаревшего синтаксиса, её прекрасно можно использовать как пособие по изучению базовых принципов построения приложений на react-native. Книга рассматривает весь процесс создания приложения, вплоть до деплоя в стор c разбором отдельных компонент: как и зачем их использовать. Примеры же отлично укрепят полученные знания, так как копипастить тут не получится и нужно будет, переосмысливая, переписывать их на новый лад.
Далее по важности: документация. Здесь прекрасно то, что она актуальна. Все новинки релизов описаны. Все устаревшие методы указаны.
Выбираем вкладку "Building Projects with Native Code" и понеслась!..
Ну и далеко не последняя пристань react-native разработчика: http://stackoverflow.com/
Далее определимся с набором инструментов для react.
Хотелось бы отметить наиболее значимые и используемые модули:
- redux
- react-redux
- redux-logger - незаменимый инструмент при отладке
- redux-saga - лучшее решение для организации сайд-эффектов
- react-redux
- селекторы
- reselect - выбор данных из состояния приложения и компоновка их в нужную структуру. Удобно вынести эту логику из редьюсеров и вьюх в специальное место.
- reselect - выбор данных из состояния приложения и компоновка их в нужную структуру. Удобно вынести эту логику из редьюсеров и вьюх в специальное место.
- jest - тестирование, идет из коробки. Главное - не пренебрегать и писать тесты =)
- eslint - инструмент для унификации стиля написания кода, а также выявления глупых и/или синстаксических ошибок.
Полезности RN
Ещё не могу не упомянуть об уже существующих библиотеках для react-native, которые несомненно упростят жизнь разработчику дабы не изобретать велосипед:
- react-native-splash-screen - создание заставки
- react-native-fontawesome - использование Font Awesome иконок из иконочного шрифта
- react-native-radio-buttons - настраиваемые radio-buttons
- react-native-slider - настраиваемый ползунок выбора значения в диапазоне
- react-native-swiper - организация небольшой галереи или слайдов
- react-native-swipe-list-view - сдвиг слево-вправо строки списка для показа дополнительных действий над ним
По работе с камерой и библиотекой фото и видео, загрузкой и шаринге есть неплохая статья на medium. А так же следующие библиотеки:
- react-native-image-picker - работа с фото и видео из библиотеки телефона
- react-native-camera - работа с камерой
- react-native-video - видеоплеер
Последние три требуют дополнительных разрешений на телефоне, таких как: доступ к библиотеке, камере, локальному хранилище данных. Нужно отметить, что эти разрешения автоматически будут запрашиваться у пользователя при установке приложения. Исключение составляют новые (выше 6-ой) версии Андроида. Поэтому их нужно запрашивать во время обращения к нужным службам приложения (и вот почему). В документации есть пример, который можно оформить в виде небольшой библиотеки:
import { PermissionsAndroid, Platform } from 'react-native'
export const requestExternalStoragePermission = async (onSuccess, onError) => {
// only for Android 6 and greater
if ((Platform.OS === 'android') && (Platform.Version > 22)) {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
{
title: 'App read external storage Permission',
message: `App needs access to your external storage
so you can take keep your data.`
}
)
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
onSuccess()
} else {
onError()
}
} catch (err) {
console.warn(err)
}
} else {
onSuccess()
}
}
Здесь можно хранить запросы и на доступ к микрофону и камере.
Как вы, наверно, уже заметили в примере выше используется модуль Platform, который позволяет задавать специфичные для различных платформ вещи. Самым простым и распространенным примером будет задание высоты системной шапки:
Андроид (пример приложения фейсбука):
iPhone (пример приложения фейсбука):
Дело в том, что при вычислении высоты экрана берется фактическая высота устройства, но реальная область, доступная для приложения для Андроида, будет меньше на высоту этой самой шапки в 20px (смотри на картинке на самую верхнуюю полосу). Тогда как в iOS "шапка" накладывается поверх приложения и не занимает дополнительного места.
Кстати, особенность верстки в React Native - это возможность легко брать высоту и ширину экрана с помощью модуля Dimensions:
const height = Dimensions.get('window').height
const width = Dimensions.get('window').width
Ну а к верстке флексами привыкаешь быстро. Важно помнить, что если у блока не заданы ширина, высота или флекс > 0, то все внутренние элементы не будут показаны (!).
Не могу не упомянуть еще одну вещь, которую вы непременно будете использовать в своем приложении, - это генерация иконок приложения для Android и iOS. Их нужно иметь тысячу и одну, чтобы приложение красиво выглядело на любом устройстве. К счастью, имея всего node 6 и ImageMagick, а также исходное изображение не менее 200х200 пикселей, через командную строку можно получить все мыслимые и немыслимые иконки. В
npm install -g yo generator-rn-toolbox
brew install imagemagick
yo rn-toolbox:assets --icon <path to your icon>
Дополнительные javascript библиотеки:
Так как код выполняется с помощью javascript, то здесь может быть любой набор библиотек на усмотрение разработчика.
На этом можно было бы и закончить, добавив пару пафосных фраз, что "всё работает из коробки", "большое комьюнити", "огромное количество плагинов". Но реальность такова, что первое впечатление может быть обманчивым и нужно пройти долгий путь в iOS- и Андроид-разработке, прежде чем получить что-то, соответствующее настоящему приложению, которое бы решало какие-то пользовательские задачи.
Подводные грабли:
Возможные ошибки в iOS:
- при создании билда в XCode сборка попадает в Other Items, из-за чего нельзя залить в AppStore.
Ошибка возникает из-за дополнительных библиотек, которые вы используете в проекте; при сборке они собираются не как используемые библиотеки, а самостоятельные проекты. Решение: во все проектах, которые находятся в Library нужно выставить
"Build Setting": Skip install = yes
- отсутствие обновления проекта при его изменении, "зависания" и прочие непредсказуемости
Одна из возможных причин кроется в том, что "clean project" в XCode не полностью удаляет создаваемые им временные файлы. Решение: удалить временные файлы вручную. Находятся они в директории:
cd /Users/[local machine]/Library/Developer/Xcode/DerivedData/
- при создании Архива для AppStore XCode ругается на дублирование файлов
Такое может произойти если вы используете pod и в нем реакт со своими компонентами, а так же часть из них напрямую из node_modules. Решение: исключить файлы при сборке проекта, добавив в ios/Podfile:
post_install do |installer|
installer.pods_project.targets.each do |target|
if target.name == "React"
target.remove_from_project
end
end
end
Для Андроида желательно привести все используемые библиотеки к одной версии.
Заключение
Дорогу осилит идущий.
Разработка приложений на React Native - это удивительный процесс открытия новых вершин и радости от того, как по-другому могут строится вещи для других платформ. Это новый, еще только зарождающийся мир, в котором ты - первооткрыватель, пусть даже порой - первооткрыватель документации.
И осилив азы, можно приступать к проектированию своего первого приложения, задавая себе все новые и новые вопросы:
- какие данные мы должны хранить в локальном сторе?
- если приложение доступно онлайн, то как оно должно вести себя при отсутствии доступа к интернету?
- в какой момент получать/отправлять данные?
- что должен видеть пользователь в этот момент?
- как и какие сообщения об ошибке показывать?
- ...
Комментарии
Добавлю, что для тестирования компонентов очень удобно использовать Enzyme. Именно на react-native я сам не использовал, но вроде как можно.
Странновато выглядит async функция с колбеками :)
export const ensureExternalStorageIsAccessible = async () => {
// only for Android 6 and greater
if ((Platform.OS === 'android') && (Platform.Version > 22)) {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
{
title: 'App read external storage Permission',
message: `App needs access to your external storage
so you can take keep your data.`
}
)
if (granted !== PermissionsAndroid.RESULTS.GRANTED) {
throw Error('Permission is not granted');
}
}
}
// а потом
try {
await ensureExternalStorageIsAccessible();
// do job
} catch (eeeh) {
// sorry, maybe next time...
}