javascript

Руководство React Native — создаем приложение под iOS. Часть 1.4 — 1.5

  • четверг, 18 мая 2017 г. в 03:14:42
https://habrahabr.ru/post/328904/
  • Разработка под iOS
  • ReactJS
  • JavaScript


→ Перевод отсюда
→ Продолжение. Предыдущие выпуски:

4. Фильтрация и отбор случайных обоев


В этом разделе мы будем отбирать определённое количество случайных обоев из заданной категории. Раздел больше посвящен JS, нежели React Native. Мы создадим новый модуль (файл), который будет генерировать случайное число. Если понятие «модуль» вам незнакомо, рекомендую обратиться к документации Node.js по модулям.
Найдите строку, объявляющую класс
class SplashWalls extends Component{/* ... */};

и выше нее добавьте следующую строку. В этой строке мы объявим константу, в которой будет храниться количество случайно сгенерированных обоев, которые мы будем показывать:
const NUM_WALLPAPERS = 5;

Теперь же мы создадим модуль, который будет генерировать случайное число. В модуле будет две функции. Давайте рассмотрим их:
  • uniqueRandomNumbers(): — функция принимает 3 аргумента. Первый — это количество случайных чисел, которые будут возвращаться. Второй и третий — это соответственно нижний (lowerLimit ) и верхний (upperLimit) пределы генерируемых чисел. Если мы вызовем функцию с аргументами uniqueRandomNumbers(5, 10, 20);, мы получим массив из 5 уникальных чисел,
    от 10 до 20.
  • randomNumberInRange(): — функция принимает два аргумента, соответственно нижний и верхний пределы генерируемых чисел. Например, в результате вызова фунцииrandomNumberInRange(2, 10);, вернется одно число от 2 до 10.

Мы могли бы объединить эти функции, но я приверженец качественного кода, поэтому следую принципу The Single Responsibility Principle, SRP (Принцип единственной ответственности — вики). SRP гласит, что каждая функция должна делать одну вещь хорошо и ничего более. Следование хорошим программистским принципам избавит от головной боли в будущем.
Создайте новый файл в том же каталоге, где лежит файл index.ios.js. Мы могли бы создать функции прямо в этом файле, но выделение их в отдельный файл позволит нам использовать их в любом другом проекте, где нам надо генерировать случайные числа. Кроме того, это не будет засорять код файла index.ios.js.
Мы назовём новый файл RandManager.js. Его содержимое показано ниже:
module.exports = {
	uniqueRandomNumbers(numRandomNumbers, lowerLimit, upperLimit) {
		var uniqueNumbers = [];
		while( uniqueNumbers.length != numRandomNumbers ) {
			var currentRandomNumber = this.randomNumberInRange(lowerLimit, upperLimit);
			if( uniqueNumbers.indexOf(currentRandomNumber) === -1 ) 
				uniqueNumbers.push(currentRandomNumber);
		}
		return uniqueNumbers;
	},

	randomNumberInRange(lowerLimit, upperLimit) {
		return Math.floor( Math.random() * (1 + upperLimit - lowerLimit) ) + lowerLimit;
	}

};

Сохраните файл. Теперь нам необходимо импортировать наш модуль в файл index.ios.js. Для этого добавьте вызов модуля после `use strict`:
'use strict';
/***/
var RandManager = require(‘./RandManager.js’);
/***/

Теперь нам надо изменить нашу функцию, получающую обои fetchWallsJSON():
fetchWallsJSON() {
  var url = 'http://unsplash.it/list';
  fetch(url)
    .then( response => response.json() )
    .then( jsonData => {
    /***/
      var randomIds = RandManager.uniqueRandomNumbers(NUM_WALLPAPERS, 0, jsonData.length);
      var walls = [];
      randomIds.forEach(randomId => {
        walls.push(jsonData[randomId]);
      });

      this.setState({
        isLoading: false,
        wallsJSON: [].concat(walls)
      });
    /***/
    })
    .catch( error => console.log('JSON Fetch error : ' + error) );
}

Как только мы получаем JSON данные, мы генерируем случайные числа и помещаем их в массив randomIds. Затем мы перебираем наши случайные числа и помещаем обои с соответствующим id в массив walls.
Затем мы обновляем переменные состояния: isLoading в false, так как данные загружены и wallsJSON в walls.
Чтобы увидеть результат, измените функцию renderResults():
renderResults() {
/***/
  var {wallsJSON, isLoading} = this.state;
  if( !isLoading ) {
    return (
      
  . <View>
        {wallsJSON.map((wallpaper, index) => {
          return(
            <Text key={index}>
              {wallpaper.id}
            </Text>
          );
        })}
       
   .</View>
    );
  }
/***/
}

В первой строке функции renderResults() мы использовали деструктуризацию из ES2015. Благодаря этому, нам удалось:
var wallsJSON = this.state.wallsJSON,
	isLoading = this.state.isLoading;

заменить на:
var {wallsJSON, isLoading} = this.state;

ES2015 крут, я же говорил вам.
В View мы перебираем массив wallsJSON, используя map().
Перебирая массив (или коллекцию) обоев при рендеринге, нам надо передать уникальный ключ (id) для каждого элемента. Поэтому мы видим свойство key:
<Text key={index}>

После обновления эмулятора мы должны увидеть следующее:

Мы видим 5 случайных id обоев. Если изменить {wallpaper.id} на {wallpaper.author} в функции renderResults(), мы должны увидеть следующее:

Отлично, мы научились извлекать случайным образом определённое количество обоев (5 в данном случае) из API. Дай пять!

5. Добавление компонента Swiper


В этом разделе мы добавим компонент Swiper. Этот компонент позволяет нам показывать обои в контейнере, который можно перелистывать вбок (Youtube (en)).
Мы научимся подключать сторонние компоненты React Native в наше приложение. У RN хорошее сообщество и на GitHub вы найдёте богатую коллекцию различных сторонних компонентов.
Для наших целей мы будем использовать react-native-swiper.
Перейдите в директорию проекта в терминале и наберите следующую команду:
npm install react-native-swiper --save

Теперь импортируем новый компонент, добавив следующую строку:
`use strict`
/***/
var Swiper = require(‘react-native-swiper’);
/***/

Давайте опробуем Swiper.
Перейдите в метод renderResults() и замените View на Swiper. После этого метод renderResults() должен выглядеть так:
renderResults() {
  var {wallsJSON, isLoading} = this.state;
  if( !isLoading ) {
    return (
    /***/
      <Swiper>
    /***/
        {wallsJSON.map((wallpaper, index) => {
          return(
            <Text key={index}>
              {wallpaper.author}
            </Text>
          );
        })}
    /***/
      </Swiper>
    /***/
    );
  }
}

Запуск в эмуляторе:

Вместо того, чтобы отображать имена авторов обоев в виде списка, мы помещаем их на разные
экраны, которые мы можем перелистывать вправо-влево (круто! — прим. переводчика).
Теперь нам надо добавить пару атрибутов:
<Swiper
/***/
dot.{<View style={{backgroundColor:'rgba(255,255,255,.4)', width: 8, height: 8,borderRadius: 10, marginLeft: 3, marginRight: 3, marginTop: 3, marginBottom: 3,}} />}

activeDot.{<View style={{backgroundColor: '#fff', width: 13, height: 13, borderRadius: 7, marginLeft: 7, marginRight: 7}} />}

loop={false}

onMomentumScrollEnd={this.onMomentumScrollEnd}
/***/
>
  {wallsJSON.map((wallpaper, index) => {
    return(
      <Text key={index}>
        {wallpaper.author}
      </Text>
    );
  })}
</Swiper>

Мы изменили:
  • Точки навигации внизу экрана стали белыми и увеличились в размере
  • Отключили перелистывание по кругу (loop={false}). То есть, когда вы дойдёте по последней страницы и попытаетесь перелистнуть дальше, вы не попадёте на первую страницу.
  • Запускаем onMomentumScrollEnd (о котором вы узнаете позже) каждый раз, как мы перелистнули страницу

На этом мы подошли к концу первой части. Какое интересное путешествие!

Подведем итоги


  1. В первом разделе мы научились создавать пустой проект RN в Xcode.
  2. Во втором разделе мы поговорили о ES2015 и почему желательно использовать новый синтаксис, также научились создавать переменные состояния (state) и извлекать JSON данные из API.
  3. В третьем разделе мы изучили динамический рендеринг приложения, в зависимости от значения переменной состояния (state). И немного познакомились с flexbox позиционированием.
  4. В четвертом разделе мы создали собственный модуль для генерации случайных чисел и научились импортировать его в приложение.
  5. В пятом разделе мы установили сторонний модуль в наше приложение, что было легко, благодаря Node.

Если быть откровенным, на данный момент наше приложение не слишком интересное. Я знаю. В следующей части мы добавим изображения обоев вместо имен авторов. Кроме того, мы добавим обработчик двойных тапов (double-tap — не знаю как точно перевести, я так понимаю это двойное нажатие пальцем по экрану, но двойным кликом это можно назвать или нет? — прим. переводчика.) с помощью компонента PanHandler. Мы научимся импортировать библиотеки в Xcode и предоставлять доступ нашему приложению к Camera Roll (по-видимому аналог «Галереи» в Android — прим. переводчика). Кроме того, мы создадим наш собственный компонент и много чего еще. Звучит интересно? Увидимся в следующей части.
PS. Как определить, где надо вставить кат?