javascript

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

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


→ Перевод отсюда
→ Продолжение. Начало здесь

2. Извлечение данных из API


В этом разделе мы будем подключаться к API сайта Unsplash.it и запрашивать информацию о обоях. Но, прежде чем мы приступим к интересному, нам надо сделать кое-что.

Объявление классов в стиле ES2015


В файле index.ios.js вы видите существующий код. Он отвечает за вывод содержимого в эмулятор.

image

В файле index.ios.js мы видим строку var SplashWalls = React.createClass({ ... }). Мы будем менять ее. В этом руководстве мы будем использовать синтаксис ES2015 для объявления классов.
Мы, разработчики, любопытные. Вы, возможно, хотите спросить: «Зачем? Зачем использовать классы из ES2015?».

Все объясняется личными предпочтениями. Я много программировал на ООП языках и class мне ближе, чем function. Кроме того, используя class мы можем писать более чистый код, потому что нам не надо добавлять (;) после объявления каждого метода.

С другой стороны мы теряем некоторые «фишки», такие как биндинг или доступ к методу isMounted(), хотя это не так важно, потому что вы не потеряете не особо много, не используя их.

Класс можно создать любым способом. Я рекомендую class. Это новая «фишка» и рано или поздно вам придётся использовать ES2015. Используя же это руководство, вам придётся использовать синтаксис ES2015, у вас просто нет выбора!

Подробнее об этом вы можете прочитать в статье “React.Component vs React.createClass” Naman Goel и Zach Silveira.

После внесения изменений код должен выглядеть так:

class SplashWalls extends Component{
  render() {
    return (
      
  . <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to React Native!
        </Text>
        <Text style={styles.instructions}>
          To get started, edit index.ios.js
        </Text>
        <Text style={styles.instructions}>
          Press Cmd+R to reload,{'\n'}
          Cmd+D or shake for dev menu
        </Text>
       
   .</View>
    );
  }
};

Людям, незнакомым с React, код, содержащийся в фигурных скобках, может показаться немного странным. Но это обычный XML-образный синтаксис, который называется JSX. Подробнее читайте здесь.

Эй! А что это за Component, экземпляр которого мы создаём? И это правильный вопрос. Если мы запустим проект сейчас, мы получим ошибку, которая сообщает, что Component не объявлен. Это можно исправить двумя способами: заменить Component на React.Component или импортировать Component, как показано ниже.

В этом и следующих примерах кода я оберну новые куски кода в /***/, чтобы вам было проще отслеживать изменения. Если вы будете копировать код отсюда, убедитесь, что вы не копируете /***/ вместе с кодом. JSX не поддерживает комментарии вида /*...*/, поэтому вставив такие комментарии, вы не сможете запустить приложение.

'use strict';
var {
  AppRegistry,
  StyleSheet,
  Tex .t,
  View,
  /***/
  Component 
  /***/
} = React;

Код, приведённый выше, избавляет вас от необходимости писать лишний код. Если не вставить эти строки кода, вам придётся писать React.AppRegistry вместо AppRegistry. Неплохо, верно? Вернитесь в Xcode и запустите проект снова, чтобы убедиться, что всё работает.

Первое, что мы должны сделать — это добавить конструктор в класс SplashWalls. В конструкторе мы инициализируем переменные состояния (state). На данный момент нам нужны две переменные:

  • wallsJSON, массив, который будет содержать json, полученный из API
  • isLoading — переменная, содержащая значение true/false и меняющая своё значение в зависимости от того, получены данные или нет.

Добавьте в код конструктор, как показано ниже:

class SplashWalls extends Component{
/***/
  constructor(props) {
    super(props);

    this.state = {
      wallsJSON: [],
      isLoading: true
    };
  }
/***/
...
}

Теперь мы создадим метод fetchWallsJSON, который будет получать json данные. Отступите несколько строк от закрывающих скобок constructor-а и добавьте следующее:

fetchWallsJSON() {
	console.log(‘Wallpapers will be fetched’);
}

Мы хотим, чтобы эта функция запускалась, как только наш компонент будет успешно смонтирован. Добавим метод componentDidMount(). Большинство методов будут добавляться в класс SplashWalls. Я буду упоминать отдельно, если методы будут добавляться в другое место.

componentDidMount() — это метод жизненного цикла, который запускается немедленно после первой отрисовки (рендера) компонента React.


Здесь можно прочитать подробнее методах жизненного цикла компонента React. Поскольку мы используем синтаксис ES2015, мы можем опустить метод getInitialState. Он заменяется объявлением переменной this.state в конструкторе.

Мне нравится разделять создаваемые мной методы от методов жизненного цикла. Вам стоит придерживаться того же правила.

Давайте объявим метод componentDidMount():

componentDidMount() {
	this.fetchWallsJSON();
}

Обратите внимание, в методе fetchWallsJSON() мы выводим сообщение в консоль. А где же сама консоль? Давайте посмотрим.

Убедитесь, что окно эмулятора находится в фокусе и нажмите Cmd + Control + Z. Из всплывающего меня выберите Debug in Chrome (отладка в Chrome). Откроется новая вкладка. Находясь в той же вкладке, перейдите в Инструменты разработчика (Option + Cmd + J). В консоли вы увидите сообщение “Wallpapers will be fetched”.


Пока не закрывайте окно отладки. Перейдите по адресу unsplash.it/list в новой вкладке. Область вкладки должна заполниться JSON массивом. Каждый элемент в нём — это JS объект, содержащий данные о отдельном файле обоев.

Давайте сделаем так, чтобы метод fetchWallsJSON() делал что-то большее, чем просто выводил сообщение в консоль.

 fetchWallsJSON() {
	/***/
    var url = 'http://unsplash.it/list';
    fetch(url)
      .then( response => response.json() )
      .then( jsonData => {
        console.log(jsonData);
      })
	.catch( error => console.log(‘Fetch error ‘ + error) );
	/***/
  }

Обновите эмулятор (Cmd + R) или, что лучше, включите live reload (живую перезагрузку), нажав Cmd + Ctrl + Z и выбрав «Enable live reload». Активировав живую перезагрузку, вам не надо будет каждый раз обновлять эмулятор после изменения кода. Просто сохраните файл в вашей IDE и эмулятор автоматически обновит отрисовку. Если раньше вы разрабатывали приложения в Xcode или Android Studio, вам очень понравится эта «фишка», потому что вы избавитесь от необходимости каждый раз заново компилировать приложение (как сказали на одной конференции по RN, теперь у вас не будет времени на чашку чая (- «Рендерится!»), как раньше — прим. переводчика).

Спустя некоторое время, после внесения изменений, вы должны увидеть в эмуляторе следующее:


Отлично, мы смогли получить JSON данные из API. Если вы заметили, перед появлением сообщения в консоли была некоторая задержка. Она связана с тем, что данные загружались с сервера, что занимает какое-то время.

Кажется самое время добавить экран, показывающий загрузку.

Экран загрузки


К концу этого раздела мы сделаем экран загрузки, который будет отображаться во время загрузки JSON-данных.

Во первых очистите все в методе render() класса SplashWall и добавьте следующие строки кода:

render() {
    var {isLoading} = this.state;
    if(isLoading)
      return this.renderLoadingMessage();
    else
      return this.renderResults();
  }

Мы указали два новых метода. Давайте объявим их:

  renderLoadingMessage() {
    return (
      
  . <View style={styles.loadingContainer}>
        <ActivityIndicatorIOS
          animating={true}
          color={'#fff'}
          size={'small'} 
          style={{margin: 15}} />
          <Text style={{color: '#fff'}}>Contacting Unsplash</Text>
       
   .</View>
    );
  }

  renderResults() {
    return (
      
  . <View>
        <Text>
          Data loaded
        </Text>
       
   .</View>
    );
  }

В зависимости от значения переменной isLoading, будут отрисовываться два компонента View. Если значение isLoading равно true, мы будем отображать индикатор загрузки и текст “Contacting Unsplash” («Соединяемся с Unsplash»). В противном случае мы будем отображать данные, вместо которых на данный момент у нас будет отображаться текст «Data loaded» («Данные загружены»).

Однако, мы забыли кое-что: мы не меняем значение переменной isLoading после загрузки данных. Давайте сделаем это. Вернемся в метод fetchWallsJSON и добавим кое-что:

fetchWallsJSON() {
    var url = 'http://unsplash.it/list';
    fetch(url)
      .then( response => response.json() )
      .then( jsonData => {
        console.log(jsonData);
	/***/
        this.setState({isLoading: false}); //update isLoading 
	/***/
      })
	.catch( error => console.log(‘Fetch error ‘ + error) );
  }

setState — это один из методов React’s Component API. Это основной метод, используемый для запуска обновления пользовательского интерфейса.

Обратите внимание в методе renderLoadingMessage мы используем новый компонент ActivityIndicatorIOS (индикатор загрузки). Нам надо импортировать его, чтобы мы могли его использовать:

'use strict';
var {
  AppRegistry,
  StyleSheet,
  Tex .t,
  View,
  Component,
/***/
  ActivityIndicatorIOS // Add new component
/***/
} = React;

Нам надо сделать еще одну вещь, прежде чем мы сможем насладиться результатом. Если вы заметили, компонент View, содержащий индикатор загрузки ActivityIndicatorIOS имеет стиль styles.loadingContainer. Нам надо задать этот стиль. Нам надо найти участок кода, начинающийся со слов var styles = StyleSheet.create({….. В этом блоке кода мы можем увидеть стили, которые уже заданы. Они относятся к дефолтному сообщению “Welcome to React Native”. Удалите все стили и задайте стили для loadingContainer, как показано ниже:

var styles = StyleSheet.create({
/***/
  loadingContainer: {
	flex: 1,
    flexDirection: 'row’,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#000'
  }
/***/
});

Все стили, которые применяются к компонентам в RN задаются таким же образом. StyleSheet.create принимает JS объект, содержащий стили. После этого, получить доступ с стилю можно с помощью оператора точка [.]. Также, как мы применили стиль для View:

<View style={styles.loadingContainer}/>

Стили также можно задавать в строке:

<View style={{
	flex: 1,
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#000'
  }} />

Это излишне загромождает код. Поэтому стили лучше хранить в переменной.

Стили очень похожи на CSS, не так ли? Это делает RN еще проще для веб-разработчиков. Когда вы работаете в IDE (Xcode, например), у вас есть StoryBoard, который позволяет напрямую перетаскивать и позиционировать на экране элементы UI, такие как кнопки. В RN это нельзя сделать, но это не так плохо в конце концов.

React Native использует flexbox для позиционирования элементов на экране. Освоив flexbox, вам не будет составлять труда позиционировать элементы. Это одна из тех вещей, которые вы должны попробовать, чтобы понять разницу.

Сохраните изменения, перейдите в эмулятор и нажмите Cmd + R. Вы должны увидеть экран загрузки, а затем экран с надписью «Data loaded» (Данные загружены):



В следующем разделе мы добавим фильтрацию обоев.