<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>@cccoding01</title><author><name>@cccoding01</name></author><id>https://teletype.in/atom/cccoding01</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/cccoding01?offset=0"></link><link rel="alternate" type="text/html" href="https://teletype.in/@cccoding01?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=cccoding01"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/cccoding01?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-07-04T13:12:54.850Z</updated><entry><id>cccoding01:_nxpb6glX-b</id><link rel="alternate" type="text/html" href="https://teletype.in/@cccoding01/_nxpb6glX-b?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=cccoding01"></link><title>Создаем приложение на JavaScript с помощью React Native</title><published>2021-05-18T14:57:15.673Z</published><updated>2021-05-18T14:57:15.673Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://teletype.in/files/0b/e8/0be835d2-8c6b-430d-bfcf-243ab15efeec.png"></media:thumbnail><summary type="html">&lt;img src=&quot;https://teletype.in/files/f7/95/f795afbc-d938-41ed-98f1-e1e9e1809d0c.png&quot;&gt;В этом уроке мы будем изучать React Native – фреймворк от компании Facebook для создания нативных приложений под iOS и Android. У него много общего с другим очень популярным фреймворком от Facebook – React Javascript, который предназначен для построения декларативных пользовательских интерфейсов.</summary><content type="html">
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://teletype.in/files/f7/95/f795afbc-d938-41ed-98f1-e1e9e1809d0c.png&quot; width=&quot;2535&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;В этом уроке мы будем изучать React Native – фреймворк от компании Facebook для создания нативных приложений под iOS и Android. У него много общего с другим очень популярным фреймворком от Facebook – &lt;a href=&quot;https://facebook.github.io/react/&quot; target=&quot;_blank&quot;&gt;React Javascript&lt;/a&gt;, который предназначен для построения декларативных пользовательских интерфейсов.&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://habrastorage.org/files/7e9/19c/4d6/7e919c4d68704387ab3085d4f444aebb.jpg&quot; width=&quot;1000&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Примечание: это обновленный вариант урока, написанного Колином Эбергардом из iOS Team, содержащий ряд правок для версии React Native 0.22.&lt;/p&gt;
  &lt;p&gt; Но на данный момент и так существует достаточно фреймворков, использующих JavaScript для создания iOS-приложений, таких как &lt;a href=&quot;http://phonegap.com/&quot; target=&quot;_blank&quot;&gt;PhoneGap&lt;/a&gt; или &lt;a href=&quot;http://www.appcelerator.com/mobile-app-development-products/&quot; target=&quot;_blank&quot;&gt;Titanium&lt;/a&gt;. Что же делает React Native особенным?&lt;/p&gt;
  &lt;p&gt; 1. В отличие от PhoneGap, в React Native логика приложения пишется и работает на JavaScript, в то время как его интерфейс остается полностью нативным. Таким образом не требуется никаких компромиссов, характерных для HTML5 UI.&lt;br /&gt; 2. В отличие от Titanium, React вводит новый оригинальный и крайне эффективный подход к созданию пользовательских интерфейсов. Если говорить кратко, UI приложения выражается как функция текущего состояния приложения.&lt;/p&gt;
  &lt;p&gt; Ключевая особенность React Native в том, что его разработчики намерены привнести модель программирования &lt;a href=&quot;https://facebook.github.io/react/&quot; target=&quot;_blank&quot;&gt;React&lt;/a&gt; в сферу разработки мобильных приложений. Важное уточнение: речь идет не о таком кроссплатформенном инструменте, с которым можно писать софт один раз и использовать его везде, а о таком, который можно изучить один раз и писать на нем везде. Данный урок предназначен для iOS-платформы, но, изучив весь изложенный материал, вы сможете без труда создавать также Android-приложения.&lt;/p&gt;
  &lt;p&gt; Если у вас есть опыт написания приложений на Objective-C или Swift, вы наверняка не обрадуетесь идее перехода на JavaScript. Но вместе с тем, второй пункт явно должен был заинтересовать Swift-разработчиков.&lt;/p&gt;
  &lt;p&gt; Несомненно, работая со Swift, вам приходилось изучать много новых и более эффективных способов шифрования алгоритмов, а также методик, способствующих преобразованию и неизменяемости. Тем не менее, способ построения UI здесь очень похож на тот, что используется при работе с Objective-C: он тоже основывается на UIKit и является императивным.&lt;/p&gt;
  &lt;p&gt; React за счет таких необычных понятий как Virtual DOM и согласование переносит функциональное программирование на слой пользовательского интерфейса.&lt;/p&gt;
  &lt;p&gt; В данном уроке по React Native мы будем создавать приложение по поиску недвижимости в Великобритании:&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://habrastorage.org/files/360/296/865/360296865d774beaac7b879c653046c3.png&quot; width=&quot;700&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Если вы никогда прежде не работали с JavaScript, не волнуйтесь. Мы подробно разберем каждый шаг разработки. React использует для стилизации синтаксис наподобие CSS, который легко прочитать и понять, но в случае чего вы всегда можете обратиться к &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS&quot; target=&quot;_blank&quot;&gt;Mozilla Developer Network&lt;/a&gt;.&lt;/p&gt;
  &lt;p&gt; Интересно? Идем дальше.&lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Приступаем к работе&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt; Для создания JavaScript-кода React Native использует &lt;a href=&quot;https://nodejs.org/en/&quot; target=&quot;_blank&quot;&gt;Node.js&lt;/a&gt;, среду выполнения JavaScript. Если вы еще не установили себе Node.js, пора это сделать.&lt;/p&gt;
  &lt;p&gt; Сначала установим &lt;a href=&quot;http://brew.sh/&quot; target=&quot;_blank&quot;&gt;Homebrew&lt;/a&gt;, следуя инструкциям на сайте, а затем – Node.js, выполнив в окне терминала следующее:&lt;/p&gt;
  &lt;pre&gt;brew install node
&lt;/pre&gt;
  &lt;p&gt;Затем с помощью &lt;strong&gt;homebrew&lt;/strong&gt; установим &lt;a href=&quot;https://facebook.github.io/watchman/&quot; target=&quot;_blank&quot;&gt;watchman&lt;/a&gt; – сервис для отслеживания изменения и поиска файлов от Facebook:&lt;/p&gt;
  &lt;pre&gt;brew install watchman
&lt;/pre&gt;
  &lt;p&gt;React Native использует его, чтобы отслеживать изменения кода и делать соответствующие правки. Это что-то вроде Xcode, но выполняющего сборку каждый раз после сохранения файла.&lt;/p&gt;
  &lt;p&gt; Далее установим React Native Command Line Interface (CLI), используя npm:&lt;/p&gt;
  &lt;pre&gt;npm install -g react-native-cli
&lt;/pre&gt;
  &lt;p&gt;Он использует &lt;a href=&quot;https://www.npmjs.com/&quot; target=&quot;_blank&quot;&gt;Node Package Manager&lt;/a&gt;, чтобы вызвать и глобально установить CLI-инструмент; npm поставляется вместе с Node.js, его функция аналогична &lt;a href=&quot;https://cocoapods.org/&quot; target=&quot;_blank&quot;&gt;CocoaPods&lt;/a&gt; или &lt;a href=&quot;https://github.com/Carthage/Carthage&quot; target=&quot;_blank&quot;&gt;Carthage&lt;/a&gt;.&lt;/p&gt;
  &lt;p&gt; Для тех, кто хочет глубже разобраться с React Native, его исходный код находится &lt;a href=&quot;https://github.com/facebook/react-native&quot; target=&quot;_blank&quot;&gt;в открытом доступе на GitHub&lt;/a&gt;.&lt;/p&gt;
  &lt;p&gt; Перейдите к папке, в которой вы хотите сохранить проект, и воспользуйтесь CLI-инструментом для его создания:&lt;/p&gt;
  &lt;pre&gt;react-native init PropertyFinder
&lt;/pre&gt;
  &lt;p&gt;Эта строка создает начальный проект, в котором содержится всё необходимое для разработки и запуска приложения на React Native.&lt;/p&gt;
  &lt;p&gt; Если вы видите уведомление об устаревшей версии Node.js, убедитесь, что та, которую установил brew, является актуальной. Для этого выполните в терминале команду &lt;strong&gt;brew link --overwrite node&lt;/strong&gt;.&lt;/p&gt;
  &lt;p&gt; Взглянув на созданные папки и файлы, вы обнаружите папку &lt;strong&gt;node_modules&lt;/strong&gt;, в которой находится фреймворк React Native. Файл &lt;strong&gt;index.ios.js&lt;/strong&gt; – это макет приложения, созданный CLI-инструментом. Обратите также внимание на папку ios – в ней содержится проект Xcode и небольшой код для интеграции с Bootstrap. Наконец, там есть и компоненты для Android, но мы не будем рассматривать их здесь.&lt;/p&gt;
  &lt;p&gt; Откройте файл проекта, сделайте его сборку и запустите. Симулятор отобразит следующее сообщение:&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://habrastorage.org/files/dad/9bf/901/dad9bf9017c740fe8f7e4738e7825978.png&quot; width=&quot;281&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;&lt;strong&gt;Примечание&lt;/strong&gt;: На момент написания урока начальный проект, созданный CLI-инструментом React Native, выводил три предупреждения во время сборки. Потому не волнуйтесь, впервые увидев какие-либо уведомления от Xcode. Разработчики React Native знают об этой небольшой проблеме, и мы работаем вместе с ними над ее устранением в следующем релизе React Native.&lt;/p&gt;
  &lt;p&gt; Вероятно, вы также заметили всплывающее окно терминала с таким сообщением:&lt;/p&gt;
  &lt;pre&gt; ┌──────────────────────────────────────────────┐
 │  Running packager on port 8081.                                            │
 │                                                                            │
 │  Keep this packager running while developing on any JS projects. Feel      │
 │  free to close this tab and run your own packager instance if you          │
 │  prefer.                                                                   │
 │                                                                            │
 │  https://github.com/facebook/react-native                                  │
 │                                                                            │
 └──────────────────────────────────────────────┘
Looking for JS files in
   /Users/tomelliott/Desktop/Scratch/PropertyFinder
 
[6:15:40 PM] &amp;lt;START&amp;gt; Building Dependency Graph
[6:15:40 PM] &amp;lt;START&amp;gt; Crawling File System
[6:15:40 PM] &amp;lt;START&amp;gt; Loading bundles layout
[6:15:40 PM] &amp;lt;END&amp;gt;   Loading bundles layout (0ms)
[Hot Module Replacement] Server listening on /hot
 
React packager ready.
 
[6:15:41 PM] &amp;lt;END&amp;gt;   Crawling File System (747ms)
[6:15:41 PM] &amp;lt;START&amp;gt; Building in-memory fs for JavaScript
[6:15:42 PM] &amp;lt;END&amp;gt;   Building in-memory fs for JavaScript (653ms)
[6:15:42 PM] &amp;lt;START&amp;gt; Building in-memory fs for Assets
[6:15:42 PM] &amp;lt;END&amp;gt;   Building in-memory fs for Assets (277ms)
[6:15:42 PM] &amp;lt;START&amp;gt; Building Haste Map
[6:15:42 PM] &amp;lt;START&amp;gt; Building (deprecated) Asset Map
[6:15:42 PM] &amp;lt;END&amp;gt;   Building (deprecated) Asset Map (49ms)
[6:15:42 PM] &amp;lt;END&amp;gt;   Building Haste Map (400ms)
[6:15:42 PM] &amp;lt;END&amp;gt;   Building Dependency Graph (2094ms)
&lt;/pre&gt;
  &lt;p&gt;Это упаковщик React Native, работающий под управлением Node.js. Вскоре вы узнаете, для чего он нужен.&lt;/p&gt;
  &lt;p&gt; Не закрывайте окно терминала, пусть оно работает на фоне. Если вы случайно закрыли его, просто остановите и перезапустите проект с помощью Xcode.&lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Примечание&lt;/strong&gt;: прежде чем мы заберемся в дебри кода, нужно определиться с выбором текстового редактора. Вам предстоит писать много JavaScript-кода, а Xcode явно не подходит для этого. Я использую &lt;a href=&quot;http://www.sublimetext.com/&quot; target=&quot;_blank&quot;&gt;Sublime Text&lt;/a&gt;, это недорогой и очень удобный инструмент. Но &lt;a href=&quot;https://atom.io/&quot; target=&quot;_blank&quot;&gt;Atom&lt;/a&gt;, &lt;a href=&quot;http://brackets.io/&quot; target=&quot;_blank&quot;&gt;Brackets&lt;/a&gt; или любой другой легковесный редактор тоже отлично подойдет.&lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Hello React Native&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt; Прежде чем начать работу над приложением по поиску недвижимости, мы создадим приложение Hello World!.. По ходу дела я буду вводить новые компоненты и понятия.&lt;/p&gt;
  &lt;p&gt; Откройте файл &lt;strong&gt;index.ios.js&lt;/strong&gt; в текстовом редакторе и удалите всё его содержимое, так как мы будем создавать приложение с нуля. Добавьте в начале файла следующее:&lt;/p&gt;
  &lt;pre&gt;&amp;#x27;use strict&amp;#x27;;
&lt;/pre&gt;
  &lt;p&gt;Эта директива объявляет &lt;strong&gt;строгий режим&lt;/strong&gt;, который добавляет улучшенную обработку ошибок и налагает ограничения на некоторые элементы JavaScript. Проще говоря, он улучшает работу JavaScript.&lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Примечание&lt;/strong&gt;: более подробную информацию о строгом режиме можно найти в статье Джона Резига под названием &lt;a href=&quot;http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/&quot; target=&quot;_blank&quot;&gt;ECMAScript 5 Strict Mode, JSON, and More&lt;/a&gt;.&lt;/p&gt;
  &lt;p&gt; Затем добавьте эту строку:&lt;/p&gt;
  &lt;pre&gt;var React = require(&amp;#x27;react-native&amp;#x27;);
&lt;/pre&gt;
  &lt;p&gt;Она загружает модуль &lt;strong&gt;react-native&lt;/strong&gt; и присваивает его переменной &lt;strong&gt;React&lt;/strong&gt;. React Native использует такую же технологию загрузки модуля, как и Node.js с функцией &lt;strong&gt;require&lt;/strong&gt;, которая примерно эквивалентна подключению и импорту библиотек в Swift.&lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Примечание&lt;/strong&gt;: более подробную информацию о модулях JavaScript можно найти в &lt;a href=&quot;https://addyosmani.com/writing-modular-js/&quot; target=&quot;_blank&quot;&gt;статье Эдди Османи о модульном JavaScript&lt;/a&gt;.&lt;/p&gt;
  &lt;p&gt; Далее добавьте следующее:&lt;/p&gt;
  &lt;pre&gt;var styles = React.StyleSheet.create({
  text: {
    color: &amp;#x27;black&amp;#x27;,
    backgroundColor: &amp;#x27;white&amp;#x27;,
    fontSize: 30,
    margin: 80
  }
});
&lt;/pre&gt;
  &lt;p&gt;Этот код задает единый стиль, который мы вскоре применим к тексту Hello World!.. Если у вас уже есть какой-либо опыт веб-разработки, вероятно, вы узнали эти свойства. Внешний вид класса StyleSheet, используемого для стилизации интерфейса, напоминает синтаксис широко применяемого в вебе языка &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS&quot; target=&quot;_blank&quot;&gt;Cascading Style Sheets (CSS)&lt;/a&gt;.&lt;/p&gt;
  &lt;p&gt; Итак, займемся непосредственно приложением. Добавьте следующий код прямо под переменной со стилями:&lt;/p&gt;
  &lt;pre&gt;class PropertyFinderApp extends React.Component {
  render() {
    return React.createElement(React.Text, {style: styles.text}, &amp;quot;Hello World!&amp;quot;);
  }
}
&lt;/pre&gt;
  &lt;p&gt;Да, это класс JavaScript.&lt;/p&gt;
  &lt;p&gt; Классы были добавлены в ECMAScript 6 (ES6). Поскольку JavaScript постоянно развивается, разработчики вынуждены ограничивать себя в используемых средствах ради сохранения совместимости со старыми системами или браузерами. И хотя iOS 9 не полностью поддерживает ES6, React Native использует инструмент под названием &lt;a href=&quot;https://babeljs.io/&quot; target=&quot;_blank&quot;&gt;Babel&lt;/a&gt;, который автоматически переводит современный JavaScript в совместимый с устаревшими версиями JavaScript там, где это необходимо.&lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Примечание&lt;/strong&gt;: если вы веб-разработчик, вы также можете использовать Babel в браузере. Так что теперь действительно не осталось оправданий для работы со старыми версиями JavaScript – даже для поддержки устаревших версий браузеров.&lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;PropertyFinderApp&lt;/strong&gt; расширяет &lt;strong&gt;React.Component&lt;/strong&gt;, основной структурный элемент интерфейса React. Компоненты содержат неизменяемые свойства и изменяемые переменные состояния; они предоставляют метод для рендеринга. Приложение, над которым мы сейчас работаем, очень простое и нуждается только в методе рендеринга.&lt;/p&gt;
  &lt;p&gt; Компоненты React Native – это не классы UIKit, а их легковесные эквиваленты. Фреймворк обеспечивает преобразование дерева компонентов React в требуемый нативный интерфейс.&lt;/p&gt;
  &lt;p&gt; Наконец, добавим в конец файла эту строку:&lt;/p&gt;
  &lt;pre&gt;React.AppRegistry.registerComponent(&amp;#x27;PropertyFinder&amp;#x27;, function() { return PropertyFinderApp });
&lt;/pre&gt;
  &lt;p&gt;&lt;strong&gt;AppRegistry&lt;/strong&gt; определяет точку входа в приложение и предоставляет корневой компонент.&lt;/p&gt;
  &lt;p&gt; Сохраните изменения в &lt;strong&gt;index.ios.js&lt;/strong&gt; и вернитесь к Xcode. Убедитесь, что схема &lt;strong&gt;PropertyFinder&lt;/strong&gt; выбрана с одним из симуляторов iPhone, а затем соберите и запустите ваш проект. Через несколько секунд на экране отобразится ваше приложение Hello World!:&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://habrastorage.org/files/5f4/1b1/f60/5f41b1f608b44e089a214d053bff7e73.png&quot; width=&quot;281&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Это JavaScript-приложение, работающее на симуляторе, который отображает нативный UI – и это без помощи браузера.&lt;/p&gt;
  &lt;p&gt; Всё еще не верите? Убедитесь сами: выберите в Xcode &lt;strong&gt;Debug\View Debugging\Capture View Hierarchy&lt;/strong&gt; и вы увидите нативную иерархию представлений. Вы также заметите повсюду сущности &lt;strong&gt;UIWebView&lt;/strong&gt;. Тест приложения отображается в &lt;strong&gt;RCTText&lt;/strong&gt;. Но что это такое? Вернитесь в Xcode, выберите &lt;strong&gt;File\Open Quickly…&lt;/strong&gt; и введите &lt;strong&gt;RCTView.h.&lt;/strong&gt; Обратите внимание, что RCTView наследует непосредственно от &lt;strong&gt;UIView.&lt;/strong&gt; Выходит, всё работает отлично.&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://habrastorage.org/files/e82/48a/8dc/e8248a8dc1bd458293c5c6f065624867.png&quot; width=&quot;1648&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Хотите знать, как это работает? Откройте в Xcode &lt;strong&gt;AppDelegate.m&lt;/strong&gt; и определите расположение &lt;strong&gt;application:didFinishLaunchingWithOptions:&lt;/strong&gt;. Этот метод создает &lt;strong&gt;RCTRootView&lt;/strong&gt;, который загружает JavaScript-приложение и рендерит результирующее представление.&lt;/p&gt;
  &lt;p&gt; Когда приложение запускается, RCTRootView загружает приложение из этого URL:&lt;/p&gt;
  &lt;pre&gt;http://localhost:8081/index.ios.bundle
&lt;/pre&gt;
  &lt;p&gt;Вспомните окно терминала, которое было открыто, когда вы запускали это приложение. Оно запускает упаковщик и сервер, который обрабатывает запрос выше.&lt;/p&gt;
  &lt;p&gt; Откройте этот URL в Safari, и вы увидите JavaScript-код вашего приложения. Вы также должны обнаружить там код Hello World!, встроенный во фреймворк React Native.&lt;/p&gt;
  &lt;p&gt; Когда ваше приложение запускается, этот код загружается и выполняется фреймворком JavaScriptCore. В нашем случае он загружает компонент &lt;strong&gt;PropertyFinderApp&lt;/strong&gt; и затем выстраивает нативное UIKit представление. Дальше в уроке мы поговорим об этом подробнее.&lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Hello World JSX&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt; Созданное приложение использует &lt;strong&gt;React.createElement&lt;/strong&gt; для построения простого интерфейса, преобразовываемого в нативный эквивалент с помощью React. И хотя текущий JavaScript-код читается легко, в случае более сложного UI со вложенными элементами он может превратиться в кашу.&lt;/p&gt;
  &lt;p&gt; Убедитесь, что приложение еще работает, затем вернитесь к редактированию файла &lt;strong&gt;index.ios.js&lt;/strong&gt; и измените оператор &lt;strong&gt;return&lt;/strong&gt; следующим образом:&lt;/p&gt;
  &lt;pre&gt;return &amp;lt;React.Text style={styles.text}&amp;gt;Hello World (Again)&amp;lt;/React.Text&amp;gt;;
&lt;/pre&gt;
  &lt;p&gt;Это &lt;a href=&quot;https://facebook.github.io/react/docs/jsx-in-depth.html&quot; target=&quot;_blank&quot;&gt;JSX&lt;/a&gt;, расширение синтаксиса JavaScript, которое добавляет в JavaScript-код синтаксис наподобие HTML. Те, у кого уже есть опыт веб-разработки, заметят сходство с последним. Мы будем использовать JSX на протяжении всего урока.&lt;/p&gt;
  &lt;p&gt; Сохраните изменения в &lt;strong&gt;index.ios.js&lt;/strong&gt; и вернитесь в симулятор. Нажмите Cmd+R, чтобы обновить сообщение на экране:&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://habrastorage.org/files/590/f19/9aa/590f199aa2a54e309cee507547ba94af.png&quot; width=&quot;281&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Перезапустить приложение на React Native так же просто, как обновить страницу браузера. Обратите внимание, что в таком случае отобразятся только те изменения, которые касались JavaScript-файлов. Во всех других случаях потребуется повторная сборка приложения в Xcode.&lt;/p&gt;
  &lt;p&gt; Поскольку в этом уроке мы будем работать с тем же набором JavaScript-компонентов, вы можете оставить приложение работать и обновлять его после сохранения изменений в &lt;strong&gt;index.ios.js&lt;/strong&gt;.&lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Примечание&lt;/strong&gt;: если вам интересно, во что преобразовывается JSX, взгляните на ‘bundle’ в браузере.&lt;/p&gt;
  &lt;p&gt; Полагаю, мы вполне наигрались с Hello World!, теперь пришло время создать настоящее приложение. &lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Добавляем навигацию&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt; Приложение Property Finder использует стандартную стековую навигацию, предоставленную навигационным контроллером UIKit. Добавим это поведение.&lt;/p&gt;
  &lt;p&gt; В файле &lt;strong&gt;index.ios.js&lt;/strong&gt; переименуйте класс &lt;strong&gt;PropertyFinderApp&lt;/strong&gt; в &lt;strong&gt;HelloWorld:&lt;/strong&gt;&lt;/p&gt;
  &lt;pre&gt;class HelloWorld extends React.Component {
&lt;/pre&gt;
  &lt;p&gt;Оставим пока текст Hello World!, но он больше не будет корневым компонентом приложения.&lt;/p&gt;
  &lt;p&gt; Затем добавим ниже компонента &lt;strong&gt;HelloWorld&lt;/strong&gt; следующий класс:&lt;/p&gt;
  &lt;pre&gt;class PropertyFinderApp extends React.Component {
  render() {
    return (
      &amp;lt;React.NavigatorIOS
        style={styles.container}
        initialRoute={{
          title: &amp;#x27;Property Finder&amp;#x27;,
          component: HelloWorld,
        }}/&amp;gt;
    );
  }
}
&lt;/pre&gt;
  &lt;p&gt;Он создает навигационный контроллер, применяет стиль и устанавливает первоначальный маршрут к компоненту HelloWorld. В веб-разработке &lt;strong&gt;маршрутизация&lt;/strong&gt; – это способ определения навигационной структуры приложения, где страницы – или &lt;em&gt;маршруты&lt;/em&gt; – привязываются к соответствующим URL.&lt;/p&gt;
  &lt;p&gt; Далее подкорректируйте стили, добавив туда параметры контейнера, как показано ниже:&lt;/p&gt;
  &lt;pre&gt;var styles = React.StyleSheet.create({
  text: {
    color: &amp;#x27;black&amp;#x27;,
    backgroundColor: &amp;#x27;white&amp;#x27;,
    fontSize: 30,
    margin: 80
  },
  container: {
    flex: 1
  }
});
&lt;/pre&gt;
  &lt;p&gt;О том, что такое &lt;strong&gt;flex: 1&lt;/strong&gt;, вы узнаете немного позже.&lt;/p&gt;
  &lt;p&gt; Сохраните изменения, вернитесь в симулятор и нажмите Cmd+R, чтобы увидеть обновленный интерфейс:&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://habrastorage.org/files/1b4/8b2/33e/1b48b233ebc8474087c5307c773afde6.png&quot; width=&quot;281&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Корневое представление навигационного контроллера соответствует тексту Hello World!.. Теперь у нас есть базовая навигационная структура текущего приложения. Пора добавить настоящий UI.&lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Создаем страницу поиска&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt; Добавьте в проект новый файл под названием &lt;strong&gt;SearchPage.js&lt;/strong&gt; и поместите его в одну папку с файлом &lt;strong&gt;index.ios.js&lt;/strong&gt;. Добавьте в новый файл этот код:&lt;/p&gt;
  &lt;pre&gt;&amp;#x27;use strict&amp;#x27;;
 
var React = require(&amp;#x27;react-native&amp;#x27;);
var {
  StyleSheet,
  Text,
  TextInput,
  View,
  TouchableHighlight,
  ActivityIndicatorIOS,
  Image,
  Component
} = React;
&lt;/pre&gt;
  &lt;p&gt;Мы уже рассматривали строгий режим и импорт в react-native, но следующий оператор присвоения – это нечто другое.&lt;/p&gt;
  &lt;p&gt; Это деструктурирующее присваивание, позволяющее извлекать множество свойств объекта и присваивать их переменным с одним оператором. Как результат, в оставшемся коде можно отбросить префикс &lt;strong&gt;React&lt;/strong&gt;. К примеру, можно обращаться напрямую к &lt;strong&gt;StyleSheet&lt;/strong&gt;, а не к &lt;strong&gt;React.StyleSheet&lt;/strong&gt;. Деструктурирование также очень удобно использовать для управления массивами. Более подробную информацию о нем &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment&quot; target=&quot;_blank&quot;&gt;можно найти в этой статье&lt;/a&gt;.&lt;/p&gt;
  &lt;p&gt; Не закрывая файл &lt;strong&gt;SearchPage.js&lt;/strong&gt;, добавьте внизу этот стиль:&lt;/p&gt;
  &lt;pre&gt;var styles = StyleSheet.create({
  description: {
    marginBottom: 20,
    fontSize: 18,
    textAlign: &amp;#x27;center&amp;#x27;,
    color: &amp;#x27;#656565&amp;#x27;
  },
  container: {
    padding: 30,
    marginTop: 65,
    alignItems: &amp;#x27;center&amp;#x27;
  }
});
&lt;/pre&gt;
  &lt;p&gt;Это тоже стандартные CSS-свойства. Возможно, данный способ задания стилей покажется вам менее удобным, чем использование Interface Builder, но этот подход определенно лучше, чем задавать свойства представления по одному в методах viewDidLoad().&lt;/p&gt;
  &lt;p&gt; Вставьте сам компонент непосредственно под стилями:&lt;/p&gt;
  &lt;pre&gt;class SearchPage extends Component {
  render() {
    return (
      &amp;lt;View style={styles.container}&amp;gt;
        &amp;lt;Text style={styles.description}&amp;gt;
          Search for houses to buy!
        &amp;lt;/Text&amp;gt;
        &amp;lt;Text style={styles.description}&amp;gt;
          Search by place-name, postcode or search near your location.
        &amp;lt;/Text&amp;gt;
      &amp;lt;/View&amp;gt;
    );
  }
}
&lt;/pre&gt;
  &lt;p&gt;&lt;strong&gt;render&lt;/strong&gt; отлично демонстрирует JSX и его структуру. Наряду со стилем вы можете очень просто визуализировать интерфейс, созданный этим компонентом: контейнер с двумя текстовыми подписями.&lt;/p&gt;
  &lt;p&gt; Напоследок добавим следующую строку в конец файла:&lt;/p&gt;
  &lt;pre&gt;module.exports = SearchPage;
&lt;/pre&gt;
  &lt;p&gt;Она экспортирует класс &lt;strong&gt;SearchPage&lt;/strong&gt;, что позволяет использовать его в других файлах.&lt;/p&gt;
  &lt;p&gt; Следующий шаг – обновить маршрутизацию приложения, чтобы установить другой первоначальный маршрут.&lt;/p&gt;
  &lt;p&gt; Откройте &lt;strong&gt;index.ios.js&lt;/strong&gt; и добавьте эту строку сразу после &lt;strong&gt;require&lt;/strong&gt; в начале файла:&lt;/p&gt;
  &lt;pre&gt;var SearchPage = require(&amp;#x27;./SearchPage&amp;#x27;);
&lt;/pre&gt;
  &lt;p&gt;В функции &lt;strong&gt;render&lt;/strong&gt; класса &lt;strong&gt;PropertyFinderApp&lt;/strong&gt; обновите &lt;strong&gt;initialRoute&lt;/strong&gt;, чтобы привязать только что созданную страницу, как показано ниже:&lt;/p&gt;
  &lt;pre&gt;component: SearchPage
&lt;/pre&gt;
  &lt;p&gt;Теперь, если хотите, можно удалить класс &lt;strong&gt;HelloWorld&lt;/strong&gt; и его стили. Они вам больше не понадобятся. &lt;br /&gt; Сохраните изменения, вернитесь в симулятор и нажмите Cmd+R, чтобы увидеть обновленный интерфейс:&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://habrastorage.org/files/5ce/2ef/d35/5ce2efd35ce943e6b03a26be8cbbc985.png&quot; width=&quot;281&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Здесь используется новый компонент &lt;strong&gt;SearchPage&lt;/strong&gt;.&lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Стилизуем с помощью Flexbox&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt; В этом уроке мы уже имели дело с некоторыми базовыми свойствами CSS, задающими параметры цвета, а также внутренних и внешних отступов. Тем не менее, вероятно, вы еще не слышали о &lt;strong&gt;flexbox&lt;/strong&gt;. Эта технология лишь недавно была добавлена в спецификацию CSS, она очень полезна при построении макетов пользовательских интерфейсов.&lt;/p&gt;
  &lt;p&gt; React Native использует библиотеку &lt;a href=&quot;https://github.com/facebook/css-layout&quot; target=&quot;_blank&quot;&gt;css-layout&lt;/a&gt;, которая является JavaScript-реализацией flexbox-стандарта, скомпилированного на C (для iOS) и на Java (для Android).&lt;br /&gt; Очень хорошо, что React Native создавался как отдельный проект, нацеленный на несколько языков программирования, так как это позволяет разрабатывать приложения с использованием новейших подходов, вроде применения &lt;a href=&quot;http://blog.scottlogic.com/2015/02/02/svg-layout-flexbox.html&quot; target=&quot;_blank&quot;&gt;flexbox-макетов к SVG&lt;/a&gt;.&lt;/p&gt;
  &lt;p&gt; По умолчанию контейнер в вашем приложении имеет направление потока данных в виде столбца, что соответствует параметру column – а значит, всё содержимое контейнера будет выстраиваться вертикально:&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://habrastorage.org/files/50d/7fb/53d/50d7fb53d8e94c18b4a95ff7874e528b.png&quot; width=&quot;634&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Это так называемая главная ось, или &lt;strong&gt;main axis&lt;/strong&gt;, она может иметь как горизонтальное, так и вертикальное направление.&lt;/p&gt;
  &lt;p&gt; Вертикальное положение каждого дочернего элемента контейнера высчитывается с учетом его внешних и внутренних отступов, а также высоты. Контейнер также задает свойству &lt;strong&gt;alignItems&lt;/strong&gt; значение &lt;strong&gt;center&lt;/strong&gt;, что определяет положение дочерних элементов на главной оси. В данном случае мы получим текст с выравниванием по центру.&lt;/p&gt;
  &lt;p&gt; Теперь добавим поле ввода и кнопки. Откройте файл &lt;strong&gt;SearchPage.js&lt;/strong&gt; и введите следующий код сразу после закрывающего тега второго элемента &lt;strong&gt;Text&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre&gt;&amp;lt;View style={styles.flowRight}&amp;gt;
  &amp;lt;TextInput
    style={styles.searchInput}
    placeholder=&amp;#x27;Search via name or postcode&amp;#x27;/&amp;gt;
  &amp;lt;TouchableHighlight style={styles.button}
      underlayColor=&amp;#x27;#99d9f4&amp;#x27;&amp;gt;
    &amp;lt;Text style={styles.buttonText}&amp;gt;Go&amp;lt;/Text&amp;gt;
  &amp;lt;/TouchableHighlight&amp;gt;
&amp;lt;/View&amp;gt;
&amp;lt;TouchableHighlight style={styles.button}
    underlayColor=&amp;#x27;#99d9f4&amp;#x27;&amp;gt;
  &amp;lt;Text style={styles.buttonText}&amp;gt;Location&amp;lt;/Text&amp;gt;
&amp;lt;/TouchableHighlight&amp;gt;
&lt;/pre&gt;
  &lt;p&gt;Мы добавили два представления высшего уровня: в одном из них находится текстовое поле ввода и кнопка, а в другом – еще одна кнопка. Сейчас вы узнаете, как можно стилизовать эти элементы&lt;/p&gt;
  &lt;p&gt; Вернитесь к параметрам стилей, поставьте запятую после блока &lt;strong&gt;container&lt;/strong&gt; и добавьте ниже новые стили:&lt;/p&gt;
  &lt;pre&gt;flowRight: {
  flexDirection: &amp;#x27;row&amp;#x27;,
  alignItems: &amp;#x27;center&amp;#x27;,
  alignSelf: &amp;#x27;stretch&amp;#x27;
},
buttonText: {
  fontSize: 18,
  color: &amp;#x27;white&amp;#x27;,
  alignSelf: &amp;#x27;center&amp;#x27;
},
button: {
  height: 36,
  flex: 1,
  flexDirection: &amp;#x27;row&amp;#x27;,
  backgroundColor: &amp;#x27;#48BBEC&amp;#x27;,
  borderColor: &amp;#x27;#48BBEC&amp;#x27;,
  borderWidth: 1,
  borderRadius: 8,
  marginBottom: 10,
  alignSelf: &amp;#x27;stretch&amp;#x27;,
  justifyContent: &amp;#x27;center&amp;#x27;
},
searchInput: {
  height: 36,
  padding: 4,
  marginRight: 5,
  flex: 4,
  fontSize: 18,
  borderWidth: 1,
  borderColor: &amp;#x27;#48BBEC&amp;#x27;,
  borderRadius: 8,
  color: &amp;#x27;#48BBEC&amp;#x27;
}
&lt;/pre&gt;
  &lt;p&gt;Следите за форматированием: каждое свойство стиля или селектор следует отделять запятой.&lt;/p&gt;
  &lt;p&gt; Эти стили предназначены для только что добавленных поля ввода и кнопок.&lt;/p&gt;
  &lt;p&gt; Сохраните изменения, вернитесь в симулятор и нажмите Cmd+R, чтобы увидеть обновленный интерфейс:&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://habrastorage.org/files/e87/b13/501/e87b135015ed4b62907646c28be1a610.png&quot; width=&quot;281&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Текстовое поле и кнопка ‘Go’ находятся на одной строке, так как вы поместили их в контейнер со стилем &lt;strong&gt;flowRight&lt;/strong&gt;, элементы которого выстраиваются в строку за счет свойства &lt;strong&gt;flexDirection: &amp;#x27;row&amp;#x27;&lt;/strong&gt;. Вместо того чтобы жестко задавать ширину каждого из этих элементов, мы выставили им относительную ширину с помощью значений свойства &lt;strong&gt;flex&lt;/strong&gt;. Таким образом, в селекторе текстового поля searchInput мы имеем &lt;strong&gt;flex: 4&lt;/strong&gt;, а в селекторе кнопки &lt;strong&gt;button — flex: 1&lt;/strong&gt;, вследствие чего их соотношение составляет 4:1.&lt;/p&gt;
  &lt;p&gt; Возможно, вы также заметили, что элементы, которые мы называем кнопками, по сути таковыми не являются. На самом деле, кнопки в UIKit – это всего лишь интерактивные текстовые надписи. Кнопки вашего приложения используют компонент React Native под названием &lt;strong&gt;TouchableHighlight&lt;/strong&gt;, который по нажатию становится прозрачным и показывает нижележащий цвет.&lt;/p&gt;
  &lt;p&gt; Наконец, добавим на страницу поиска изображение. Вы можете скачать его в нескольких разрешениях &lt;a href=&quot;http://www.raywenderlich.com/wp-content/uploads/2015/03/ReactNative-HouseImage.zip&quot; target=&quot;_blank&quot;&gt;одним архивом&lt;/a&gt;. После скачивания распакуйте архив.&lt;/p&gt;
  &lt;p&gt; Далее создадим в корневом проекте директорию под названием ’Resources’ и поместим в нее все три изображения.&lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Предметные каталоги&lt;/strong&gt;: Как вам известно, специалисты из Apple рекомендуют по возможности помещать изображения в предметные каталоги. Тем не менее, для React Native это &lt;a href=&quot;http://facebook.github.io/react-native/docs/images.html#content&quot; target=&quot;_blank&quot;&gt;наоборот нежелательно&lt;/a&gt;. Хранение цифровых объектов приложения рядом с его компонентами дает несколько преимуществ. Во-первых, это позволяет сохранить независимость компонентов. Во-вторых, при добавлении новых изображений не требуется повторная загрузка приложения. И в-третьих, при разработке приложения для iOS и Android это дает возможность хранить изображения для двух платформ в одном месте.&lt;/p&gt;
  &lt;p&gt; Вернитесь к файлу &lt;strong&gt;SearchPage.js&lt;/strong&gt; и добавьте эту строку под закрывающим тегом компонента &lt;strong&gt;TouchableHighlight&lt;/strong&gt;, отвечающего за кнопку &lt;strong&gt;location&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre&gt;&amp;lt;Image source={require(&amp;#x27;./Resources/house.png&amp;#x27;)} style={styles.image}/&amp;gt;
&lt;/pre&gt;
  &lt;p&gt;Теперь добавьте соответствующий стиль изображения в блоке со стилями, не забыв поставить запятую после предыдущего селектора:&lt;/p&gt;
  &lt;pre&gt;image: {
  width: 217,
  height: 138
}
&lt;/pre&gt;
  &lt;p&gt;Сохраните изменения. Вернитесь в симулятор и нажмите Cmd+R, чтобы увидеть новый интерфейс:&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://habrastorage.org/files/60d/14f/b1e/60d14fb1e92b4e079148b3fc51dacf40.png&quot; width=&quot;281&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;&lt;strong&gt;Примечание&lt;/strong&gt;: Если изображение с домом не отображается, а вместо него показано уведомление о том, что картинка не найдена, попробуйте перезапустить упаковщик с помощью команды npm start в терминале.&lt;/p&gt;
  &lt;p&gt; Наше приложение уже смотрится симпатично, но всё же чего-то не хватает. Нужно добавить состояние приложения и выполнить кое-какие действия.&lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Добавляем состояние компонента&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt; Каждый компонент в React имеет собственный объект состояния, который используется как хранилище типа «ключ–значение». Прежде чем компонент отобразится, нужно задать начальное состояние.&lt;/p&gt;
  &lt;p&gt; В файле &lt;strong&gt;SearchPage.js&lt;/strong&gt; добавьте следующий код в класс &lt;strong&gt;SearchPage&lt;/strong&gt;, прямо перед &lt;strong&gt;render()&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre&gt;constructor(props) {
  super(props);
  this.state = {
    searchString: &amp;#x27;london&amp;#x27;
  };
}
&lt;/pre&gt;
  &lt;p&gt;Теперь у вашего компонента есть переменная &lt;strong&gt;state&lt;/strong&gt;, а начальным значением &lt;strong&gt;searchString&lt;/strong&gt; является &lt;strong&gt;london&lt;/strong&gt;.&lt;/p&gt;
  &lt;p&gt; Время воспользоваться этим состоянием компонента. Изменим элемент &lt;strong&gt;TextInput&lt;/strong&gt; в &lt;strong&gt;render&lt;/strong&gt;, как показано ниже:&lt;/p&gt;
  &lt;pre&gt;&amp;lt;TextInput
  style={styles.searchInput}
  value={this.state.searchString}
  placeholder=&amp;#x27;Search via name or postcode&amp;#x27;/&amp;gt;
&lt;/pre&gt;
  &lt;p&gt;Мы выставили значение свойства &lt;strong&gt;TextInput&lt;/strong&gt; – то есть показываемого пользователю текста – на текущее значение переменной состояния &lt;strong&gt;searchString&lt;/strong&gt;. Итак, мы позаботились о начальном состоянии. Но что будет, когда пользователь отредактирует этот текст?&lt;/p&gt;
  &lt;p&gt; Прежде всего, создадим метод, выступающий в роли обработчика событий. Перейдите к классу &lt;strong&gt;SearchPage&lt;/strong&gt; и добавьте данный метод сразу после &lt;strong&gt;constructor&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre&gt;onSearchTextChanged(event) {
  console.log(&amp;#x27;onSearchTextChanged&amp;#x27;);
  this.setState({ searchString: event.nativeEvent.text });
  console.log(this.state.searchString);
}
&lt;/pre&gt;
  &lt;p&gt;Он берет значение из свойства &lt;strong&gt;text&lt;/strong&gt; в событии родного браузера и использует его для обновления состояния компонента. Он также добавляет код для сбора данных, которые нам вскоре пригодятся.&lt;/p&gt;
  &lt;p&gt; Чтобы данный метод вызывался каждый раз при изменении текста, вернемся к полю &lt;strong&gt;TextInput&lt;/strong&gt; метода &lt;strong&gt;render&lt;/strong&gt; и добавим свойство &lt;strong&gt;onChange&lt;/strong&gt;. В итоге тег примет следующий вид:&lt;/p&gt;
  &lt;pre&gt;&amp;lt;TextInput
  style={styles.searchInput}
  value={this.state.searchString}
  onChange={this.onSearchTextChanged.bind(this)}
  placeholder=&amp;#x27;Search via name or postcode&amp;#x27;/&amp;gt;
&lt;/pre&gt;
  &lt;p&gt;Когда пользователь меняет текст, вызывается функция, добавленная к свойству &lt;strong&gt;onChange&lt;/strong&gt; (в данном случае это &lt;strong&gt;onSearchTextChanged&lt;/strong&gt;).&lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Примечание&lt;/strong&gt;: Возможно, вам непонятно, для чего нужно выражение &lt;strong&gt;bind(this)&lt;/strong&gt;. JavaScript интерпретирует ключевое слово &lt;strong&gt;this&lt;/strong&gt; немного иначе, чем большинство других языков. В Swift данному слову соответствует &lt;strong&gt;self&lt;/strong&gt;. Использование &lt;strong&gt;bind&lt;/strong&gt; в данном контексте гарантирует, что &lt;strong&gt;this&lt;/strong&gt; внутри метода &lt;strong&gt;onSearchTextChanged&lt;/strong&gt; является отсылкой к экземпляру компонента. Дополнительную информацию о ключевом слове &lt;strong&gt;this&lt;/strong&gt; можно получить на &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this&quot; target=&quot;_blank&quot;&gt;MDN&lt;/a&gt;.&lt;/p&gt;
  &lt;p&gt; Прежде чем мы снова обновим приложение, добавим оператор log в начале &lt;strong&gt;render()&lt;/strong&gt;, сразу перед &lt;strong&gt;return&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre&gt;console.log(&amp;#x27;SearchPage.render&amp;#x27;);
&lt;/pre&gt;
  &lt;p&gt;Вам предстоит узнать нечто очень любопытное об этих операторах.&lt;/p&gt;
  &lt;p&gt; Сохраните изменения, вернитесь в симулятор и нажмите Cmd+R. Вы увидите, что теперь начальным значением поля ввода является ‘london’, а при редактировании текста в консоль Xcode записываются какие-то выражения:&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://habrastorage.org/files/616/2d2/6a0/6162d26a03d64727a6d331f77aeed419.png&quot; width=&quot;235&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Если вы внимательно посмотрите на скриншот выше, то можете заподозрить, что порядок записи выражений немного нарушен:&lt;/p&gt;
  &lt;p&gt; 1. Это первоначальный вызов &lt;strong&gt;render()&lt;/strong&gt;, необходимый чтобы настроить представление.&lt;br /&gt; 2. При изменении текста вызывается &lt;strong&gt;onSearchTextChanged()&lt;/strong&gt;.&lt;br /&gt; 3. Затем обновляется состояние компонента, чтобы отобразить только что введенный текст, который повторно запускает &lt;strong&gt;render&lt;/strong&gt;. &lt;br /&gt; 4. &lt;strong&gt;onSearchTextChanged()&lt;/strong&gt; завершает всё, записывая новую строку поиска.&lt;/p&gt;
  &lt;p&gt; Когда приложение обновляет состояние любого компонента React, это запускает повторный рендеринг всего пользовательского интерфейса, который, в свою очередь, вызывает &lt;strong&gt;render&lt;/strong&gt; всех компонентов. Это превосходная идея, так как в этом случае логика рендеринга полностью отделяется от изменений состояния, которые затрагивают UI. &lt;/p&gt;
  &lt;p&gt; В большинстве UI-фреймворков разработчику нужно либо вручную обновлять интерфейс в зависимости от изменений состояния, либо делать это посредством каких-либо вспомогательных фреймворков, которые создают неявную связь между состоянием приложения и его представлением в UI. Что касается второго варианта, по этому поводу можно ознакомиться со статьей о применении &lt;a href=&quot;https://www.raywenderlich.com/74106/mvvm-tutorial-with-reactivecocoa-part-1&quot; target=&quot;_blank&quot;&gt;шаблона MVVM совместно с фреймворком ReactiveCocoa&lt;/a&gt;.&lt;/p&gt;
  &lt;p&gt; С React вам больше не придется волноваться о том, какие части UI могут быть затронуты изменением состояния, так как весь интерфейс выражается в виде функции состояния приложения.&lt;/p&gt;
  &lt;p&gt; На данном этапе вы, скорее всего, заметили один изъян данного подхода. Совершенно верно, дело в производительности.&lt;/p&gt;
  &lt;p&gt; Конечно, нельзя просто так отбрасывать весь интерфейс и перестраивать его каждый раз, когда что-то меняется. Вот где React по-настоящему проявляет себя. Каждый раз, когда интерфейс рендерится, он берет дерево видимых объектов, которое возвращают методы render, и согласовывает его с текущим представлением UIKit. В результате этого согласования получается список обновлений, которые React должен применить к текущему представлению. Таким образом, повторному рендерингу подвергнутся только те объекты, которые на самом деле были изменены.&lt;/p&gt;
  &lt;p&gt; Разве не здорово видеть, как в нашем iOS-приложении применяются новейшие подходы, за счет которых ReactJS является таким уникальным: virtual-DOM (объектная модель документа, визуальное дерево веб-документа) и согласование?&lt;/p&gt;
  &lt;p&gt; Позже у вас будет возможность разобраться с этим подробнее, а пока нужно еще поработать над приложением. Для начала удалим код сбора данных, который мы добавили ранее, так как он только засоряет общий код.&lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Настраиваем поиск&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt; Чтобы реализовать поиск, нужно обработать нажатие кнопки ‘Go’, создать необходимый API-запрос и предоставить пользователю визуальное подтверждение того, что запрос обрабатывается.&lt;/p&gt;
  &lt;p&gt; Откройте файл &lt;strong&gt;SearchPage.js&lt;/strong&gt;, найдите constructor и обновите внутри него начальное состояние:&lt;/p&gt;
  &lt;pre&gt;this.state = {
  searchString: &amp;#x27;london&amp;#x27;,
  isLoading: false
};
&lt;/pre&gt;
  &lt;p&gt;Новое свойство &lt;strong&gt;isLoading&lt;/strong&gt; будет следить за тем, обрабатывается ли запрос. &lt;/p&gt;
  &lt;p&gt; Добавьте такую логику в начале &lt;strong&gt;render&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre&gt;var spinner = this.state.isLoading ?
  ( &amp;lt;ActivityIndicatorIOS
      size=&amp;#x27;large&amp;#x27;/&amp;gt; ) :
  ( &amp;lt;View/&amp;gt;);
&lt;/pre&gt;
  &lt;p&gt;Это тернарный оператор &lt;strong&gt;if&lt;/strong&gt;, который либо добавляет индикатор выполнения действия, либо отображает пустой экран – в зависимости от состояния компонента &lt;strong&gt;isLoading&lt;/strong&gt;. Поскольку весь компонент рендерится каждый раз заново, вы можете спокойно смешивать логику JSX и JavaScript.&lt;/p&gt;
  &lt;p&gt; Чтобы добавить на страницу индикатор загрузки, перейдите к JSX, отвечающему за интерфейс поиска в &lt;strong&gt;return&lt;/strong&gt;, и вставьте под &lt;strong&gt;Image&lt;/strong&gt; эту строку:&lt;/p&gt;
  &lt;pre&gt;{spinner}
&lt;/pre&gt;
  &lt;p&gt;Затем добавьте данные методы в класс &lt;strong&gt;SearchPage&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre&gt;_executeQuery(query) {
  console.log(query);
  this.setState({ isLoading: true });
}
 
onSearchPressed() {
  var query = urlForQueryAndPage(&amp;#x27;place_name&amp;#x27;, this.state.searchString, 1);
  this._executeQuery(query);
}
&lt;/pre&gt;
  &lt;p&gt;Метод &lt;strong&gt;_executeQuery()&lt;/strong&gt; впоследствии будет выполнять запрос, но пока он просто заносит сообщение в консоль и необходимым образом настраивает компонент &lt;strong&gt;isLoading&lt;/strong&gt;, чтобы в интерфейсе отобразилось новое состояние.&lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Примечание&lt;/strong&gt;: Классы в JavaScript не имеют модификаторов доступа, потому ключевого слова ‘private’ для них тоже не существует. В силу этого многие разработчики часто дают методам префикс в виде нижнего подчеркивания, чтобы указать, что они являются private.&lt;/p&gt;
  &lt;p&gt; Метод &lt;strong&gt;onSearchPressed()&lt;/strong&gt; настраивает и отправляет запрос. Он должен срабатывать по нажатию кнопки ‘Go’. Чтобы реализовать это, вернитесь к &lt;strong&gt;render&lt;/strong&gt; и добавьте следующее свойство внутри открывающего тега компонента &lt;strong&gt;TouchableHighlight&lt;/strong&gt;, отвечающего за текст ‘Go’:&lt;/p&gt;
  &lt;pre&gt;onPress={this.onSearchPressed.bind(this)}
&lt;/pre&gt;
  &lt;p&gt;Наконец, добавьте эту служебную функцию над объявлением класса SearchPage:&lt;/p&gt;
  &lt;pre&gt;function urlForQueryAndPage(key, value, pageNumber) {
  var data = {
      country: &amp;#x27;uk&amp;#x27;,
      pretty: &amp;#x27;1&amp;#x27;,
      encoding: &amp;#x27;json&amp;#x27;,
      listing_type: &amp;#x27;buy&amp;#x27;,
      action: &amp;#x27;search_listings&amp;#x27;,
      page: pageNumber
  };
  data[key] = value;
 
  var querystring = Object.keys(data)
    .map(key =&amp;gt; key + &amp;#x27;=&amp;#x27; + encodeURIComponent(data[key]))
    .join(&amp;#x27;&amp;amp;&amp;#x27;);
 
  return &amp;#x27;http://api.nestoria.co.uk/api?&amp;#x27; + querystring;
};
&lt;/pre&gt;
  &lt;p&gt;Эта функция не зависит от &lt;strong&gt;SearchPage&lt;/strong&gt;, потому она реализуется скорее как свободная функция, а не как метод. Сначала она создает строку запроса, основываясь на параметрах данных. Исходя из них, она преобразовывает данные в требуемый формат строки: пары name=value, разделенные амперсандами. Синтаксис =&amp;gt; соответствует стрелочной функции, еще одному &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions&quot; target=&quot;_blank&quot;&gt;недавнему дополнению в JavaScript&lt;/a&gt;. Стрелочные функции предоставляют более лаконичный синтаксис для создания анонимных функций.&lt;/p&gt;
  &lt;p&gt; Сохраните изменения, вернитесь к симулятору, перезагрузите страницу с помощью комбинации Cmd+R и нажмите кнопку ‘Go’. На экране отобразится индикатор загрузки. Обратите внимание на консоль Xcode:&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://habrastorage.org/files/1f7/b64/026/1f7b640260fe4b958e620b6588125a08.png&quot; width=&quot;700&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;На экране показан индикатор активности, а в логе появляется URL для требуемого запроса. Откройте этот URL в браузере, чтобы увидеть результат: большой JSON-объект. Но не волнуйтесь, вам не нужно будет вникать в него. Сейчас мы добавим код и проведем его парсинг. &lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Примечание&lt;/strong&gt;: Данное приложение использует для &lt;a href=&quot;http://www.nestoria.co.uk/help/api&quot; target=&quot;_blank&quot;&gt;поиска недвижимости Nestoria API&lt;/a&gt;. JSON-ответ, который приходит из API, весьма незамысловат. Так или иначе, вы всегда можете просмотреть документацию на предмет предполагаемого формата URL-запросов и ответов. &lt;/p&gt;
  &lt;p&gt; Следующий шаг – выполнить запрос из приложения.&lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Выполняем API-запрос&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt; Не закрывая файл &lt;strong&gt;SearchPage.js&lt;/strong&gt;, обновите начальное положение в конструкторе класса, чтобы добавить переменную &lt;strong&gt;message&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre&gt;this.state = {
  searchString: &amp;#x27;london&amp;#x27;,
  isLoading: false,
  message: &amp;#x27;&amp;#x27;
};
&lt;/pre&gt;
  &lt;p&gt;Найдите &lt;strong&gt;render&lt;/strong&gt; и добавьте внутри него следующую строку:&lt;/p&gt;
  &lt;pre&gt;&amp;lt;Text style={styles.description}&amp;gt;{this.state.message}&amp;lt;/Text&amp;gt;
&lt;/pre&gt;
  &lt;p&gt;Она отвечает за отображение внизу экрана сообщений для пользователя. &lt;/p&gt;
  &lt;p&gt; Найдите класс &lt;strong&gt;SearchPage&lt;/strong&gt; и добавьте в конец метода &lt;strong&gt;_executeQuery()&lt;/strong&gt; данный код:&lt;/p&gt;
  &lt;pre&gt;fetch(query)
  .then(response =&amp;gt; response.json())
  .then(json =&amp;gt; this._handleResponse(json.response))
  .catch(error =&amp;gt;
     this.setState({
      isLoading: false,
      message: &amp;#x27;Something bad happened &amp;#x27; + error
   }));
&lt;/pre&gt;
  &lt;p&gt;Он использует функцию &lt;strong&gt;fetch&lt;/strong&gt;, которая является &lt;a href=&quot;https://fetch.spec.whatwg.org/&quot; target=&quot;_blank&quot;&gt;частью Web API&lt;/a&gt; и предоставляет значительно улучшенный API по сравнению с XMLHttpRequest. Асинхронный ответ возвращается в виде объекта &lt;a href=&quot;http://www.html5rocks.com/en/tutorials/es6/promises/&quot; target=&quot;_blank&quot;&gt;promise&lt;/a&gt;, и в случае успеха выполняется парсинг JSON-объекта, который затем передается в метод &lt;strong&gt;_handleResponse&lt;/strong&gt; (мы добавим его немного позже). &lt;/p&gt;
  &lt;p&gt; Наконец, добавим эту функцию в &lt;strong&gt;SearchPage&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre&gt;_handleResponse(response) {
  this.setState({ isLoading: false , message: &amp;#x27;&amp;#x27; });
  if (response.application_response_code.substr(0, 1) === &amp;#x27;1&amp;#x27;) {
    console.log(&amp;#x27;Properties found: &amp;#x27; + response.listings.length);
  } else {
    this.setState({ message: &amp;#x27;Location not recognized; please try again.&amp;#x27;});
  }
}
&lt;/pre&gt;
  &lt;p&gt;Она очищает &lt;strong&gt;isLoading&lt;/strong&gt; и при успешном запросе добавляет в лог количество найденных объектов недвижимости.&lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Примечание&lt;/strong&gt;: В Nestoria API есть ряд весьма полезных &lt;a href=&quot;http://www.nestoria.co.uk/help/api-return-codes&quot; target=&quot;_blank&quot;&gt;кодов ответа сервера&lt;/a&gt;. К примеру, коды 202 и 200 возвращают список локаций, подобранных по принципу наилучшего выбора. Почему бы не воспользоваться этой опцией и не предоставить пользователям несколько дополнительных предложений?&lt;/p&gt;
  &lt;p&gt; Сохраните изменения, вернитесь в симулятор и нажмите Cmd+R. Попробуйте ввести поисковый запрос ‘london’. Вы должны увидеть в логе сообщение о том, что было найдено 20 объектов недвижимости (стандартное для результата количество). А теперь попробуйте ввести неверный запрос, например ‘narnia’. Вы увидите следующее сообщение:&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://habrastorage.org/files/506/bb9/eb8/506bb9eb84c64a9f880a824d7ee3f6bb.png&quot; width=&quot;281&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Время поработать над выводом результата поиска на экран.&lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Выводим результат поиска&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt; Создайте новый файл под названием &lt;strong&gt;SearchResults.js&lt;/strong&gt; и добавьте в него следующее:&lt;/p&gt;
  &lt;pre&gt;&amp;#x27;use strict&amp;#x27;;
 
var React = require(&amp;#x27;react-native&amp;#x27;);
var {
  StyleSheet,
  Image,
  View,
  TouchableHighlight,
  ListView,
  Text,
  Component
} = React;
&lt;/pre&gt;
  &lt;p&gt;Всё верно, это выражение &lt;strong&gt;require&lt;/strong&gt;, включающее модуль &lt;strong&gt;react-native&lt;/strong&gt; и деструктурирующее присваивание.&lt;/p&gt;
  &lt;p&gt; Затем добавьте сам компонент:&lt;/p&gt;
  &lt;pre&gt;class SearchResults extends Component {
 
  constructor(props) {
    super(props);
    var dataSource = new ListView.DataSource(
      {rowHasChanged: (r1, r2) =&amp;gt; r1.guid !== r2.guid});
    this.state = {
      dataSource: dataSource.cloneWithRows(this.props.listings)
    };
  }
 
  renderRow(rowData, sectionID, rowID) {
    return (
      &amp;lt;TouchableHighlight
          underlayColor=&amp;#x27;#dddddd&amp;#x27;&amp;gt;
        &amp;lt;View&amp;gt;
          &amp;lt;Text&amp;gt;{rowData.title}&amp;lt;/Text&amp;gt;
        &amp;lt;/View&amp;gt;
      &amp;lt;/TouchableHighlight&amp;gt;
    );
  }
 
  render() {
    return (
      &amp;lt;ListView
        dataSource={this.state.dataSource}
        renderRow={this.renderRow.bind(this)}/&amp;gt;
    );
  }
 
}
&lt;/pre&gt;
  &lt;p&gt;Код выше использует специальный компонент – &lt;strong&gt;ListView&lt;/strong&gt;, который отображает данные внутри контейнера прокрутки в несколько рядов, почти как в &lt;strong&gt;UITableView&lt;/strong&gt;. Данные попадают в &lt;strong&gt;ListView&lt;/strong&gt; через &lt;strong&gt;ListView.DataSource&lt;/strong&gt; и функцию, передающую UI для каждого ряда.&lt;/p&gt;
  &lt;p&gt; Создавая источник данных, вы предоставляете функцию, которая проверяет на идентичность пару рядов. &lt;strong&gt;ListView&lt;/strong&gt; затем использует результат во время процесса согласования, чтобы выявить изменения в данных списка. В нашем примере Nestoria API возвращает объекты недвижимости со свойством &lt;strong&gt;guid&lt;/strong&gt;, что хорошо подходит для наших целей.&lt;/p&gt;
  &lt;p&gt; Добавьте в конец файла экспорт модуля:&lt;/p&gt;
  &lt;pre&gt;module.exports = SearchResults;
&lt;/pre&gt;
  &lt;p&gt;А эту строку нужно вставить в начале файла &lt;strong&gt;SearchPage.js&lt;/strong&gt;, ниже вызова &lt;strong&gt;require&lt;/strong&gt; для React:&lt;/p&gt;
  &lt;pre&gt;var SearchResults = require(&amp;#x27;./SearchResults&amp;#x27;);
&lt;/pre&gt;
  &lt;p&gt;Это позволит нам использовать класс &lt;strong&gt;SearchResults&lt;/strong&gt; изнутри класса &lt;strong&gt;SearchPage&lt;/strong&gt;: &lt;/p&gt;
  &lt;p&gt; Измените метод &lt;strong&gt;_handleResponse&lt;/strong&gt;, заменив выражение &lt;strong&gt;console.log&lt;/strong&gt; на следующее:&lt;/p&gt;
  &lt;pre&gt;this.props.navigator.push({
  title: &amp;#x27;Results&amp;#x27;,
  component: SearchResults,
  passProps: {listings: response.listings}
});
&lt;/pre&gt;
  &lt;p&gt;Этот код переходит к компоненту &lt;strong&gt;SearchResults&lt;/strong&gt; и передает объекты недвижимости из API-запроса. Использование push-метода обеспечивает загрузку результатов поиска в стек переходов, вследствие чего у вас появится кнопка ‘Back’, чтобы вернуться в корневой каталог.&lt;/p&gt;
  &lt;p&gt; Сохраните изменения, вернитесь в симулятор, нажмите Cmd+R и попробуйте выполнить поиск. Вы увидите список объектов недвижимости:&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://habrastorage.org/files/c1f/b0e/3b2/c1fb0e3b205e4dad81dac2d8000e852c.png&quot; width=&quot;281&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Наконец-то мы получили настоящий список. Правда, выглядит он пока скучновато. Давайте немного преобразим его.&lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Применяем стилизацию&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt; Постепенно код React Native начинает приобретать знакомый вам вид, поэтому мы немного ускорим темп работы.&lt;/p&gt;
  &lt;p&gt; Добавим данное определение стиля сразу после деструктурирующего присваивания в файле &lt;strong&gt;SearchResults.js&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre&gt;var styles = StyleSheet.create({
  thumb: {
    width: 80,
    height: 80,
    marginRight: 10
  },
  textContainer: {
    flex: 1
  },
  separator: {
    height: 1,
    backgroundColor: &amp;#x27;#dddddd&amp;#x27;
  },
  price: {
    fontSize: 25,
    fontWeight: &amp;#x27;bold&amp;#x27;,
    color: &amp;#x27;#48BBEC&amp;#x27;
  },
  title: {
    fontSize: 20,
    color: &amp;#x27;#656565&amp;#x27;
  },
  rowContainer: {
    flexDirection: &amp;#x27;row&amp;#x27;,
    padding: 10
  }
});
&lt;/pre&gt;
  &lt;p&gt;Здесь содержатся все стили для отображения каждого ряда данных.&lt;/p&gt;
  &lt;p&gt; Заменим &lt;strong&gt;renderRow()&lt;/strong&gt; следующим кодом:&lt;/p&gt;
  &lt;pre&gt;renderRow(rowData, sectionID, rowID) {
  var price = rowData.price_formatted.split(&amp;#x27; &amp;#x27;)[0];
 
  return (
    &amp;lt;TouchableHighlight onPress={() =&amp;gt; this.rowPressed(rowData.guid)}
        underlayColor=&amp;#x27;#dddddd&amp;#x27;&amp;gt;
      &amp;lt;View&amp;gt;
        &amp;lt;View style={styles.rowContainer}&amp;gt;
          &amp;lt;Image style={styles.thumb} source={{ uri: rowData.img_url }} /&amp;gt;
          &amp;lt;View  style={styles.textContainer}&amp;gt;
            &amp;lt;Text style={styles.price}&amp;gt;£{price}&amp;lt;/Text&amp;gt;
            &amp;lt;Text style={styles.title}
                  numberOfLines={1}&amp;gt;{rowData.title}&amp;lt;/Text&amp;gt;
          &amp;lt;/View&amp;gt;
        &amp;lt;/View&amp;gt;
        &amp;lt;View style={styles.separator}/&amp;gt;
      &amp;lt;/View&amp;gt;
    &amp;lt;/TouchableHighlight&amp;gt;
  );
}
&lt;/pre&gt;
  &lt;p&gt;Этот код обрабатывает данные цен, полученных в формате ‘300,000 GBP’ и убирает оттуда GBP. Затем он отображает строку интерфейса, используя подход, с которым вы, скорее всего, уже хорошо знакомы. Изображение (&lt;strong&gt;Image&lt;/strong&gt;) загружается из возвращенного URL (&lt;strong&gt;rowData.img_url&lt;/strong&gt;), который React Native берет из основного потока, и добавляется в ряд.&lt;/p&gt;
  &lt;p&gt; Также обратите внимание на использование стрелочной функции в свойстве &lt;strong&gt;onPress&lt;/strong&gt; компонента &lt;strong&gt;TouchableHighlight&lt;/strong&gt;. С ее помощью захватывается &lt;strong&gt;guid&lt;/strong&gt; для ряда.&lt;/p&gt;
  &lt;p&gt; Последний шаг – добавить этот метод в класс, чтобы управлять нажатием на экран:&lt;/p&gt;
  &lt;pre&gt;rowPressed(propertyGuid) {
  var property = this.props.listings.filter(prop =&amp;gt; prop.guid === propertyGuid)[0];
}
&lt;/pre&gt;
  &lt;p&gt;Этот метод определяет, какой объект недвижимости был выбран пользователем. Правда, сейчас он не работает, но мы это скоро исправим. А пока любуйтесь результатом.&lt;/p&gt;
  &lt;p&gt; Сохраните изменения, вернитесь в симулятор и нажмите Cmd+R, чтобы увидеть обновленный список:&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://habrastorage.org/files/545/670/a1b/545670a1bd97447cbb76369e93f8834d.png&quot; width=&quot;281&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Выглядит отлично… если закрыть глаза на цены.&lt;/p&gt;
  &lt;p&gt; Наконец, пришло время добавить последнюю страницу.&lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Добавляем страницу просмотра информации о недвижимости&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt; Создайте в проекте новый файл под названием &lt;strong&gt;PropertyView.js&lt;/strong&gt; и введите туда этот код:&lt;/p&gt;
  &lt;pre&gt;&amp;#x27;use strict&amp;#x27;;
 
var React = require(&amp;#x27;react-native&amp;#x27;);
var {
  StyleSheet,
  Image,
  View,
  Text,
  Component
} = React;
&lt;/pre&gt;
  &lt;p&gt;Уверен, вы уже способны набрать его даже с закрытыми глазами. &lt;/p&gt;
  &lt;p&gt; Теперь добавим стили:&lt;/p&gt;
  &lt;pre&gt;var styles = StyleSheet.create({
  container: {
    marginTop: 65
  },
  heading: {
    backgroundColor: &amp;#x27;#F8F8F8&amp;#x27;,
  },
  separator: {
    height: 1,
    backgroundColor: &amp;#x27;#DDDDDD&amp;#x27;
  },
  image: {
    width: 400,
    height: 300
  },
  price: {
    fontSize: 25,
    fontWeight: &amp;#x27;bold&amp;#x27;,
    margin: 5,
    color: &amp;#x27;#48BBEC&amp;#x27;
  },
  title: {
    fontSize: 20,
    margin: 5,
    color: &amp;#x27;#656565&amp;#x27;
  },
  description: {
    fontSize: 18,
    margin: 5,
    color: &amp;#x27;#656565&amp;#x27;
  }
});
&lt;/pre&gt;
  &lt;p&gt;И сам компонент:&lt;/p&gt;
  &lt;pre&gt;class PropertyView extends Component {
 
  render() {
    var property = this.props.property;
    var stats = property.bedroom_number + &amp;#x27; bed &amp;#x27; + property.property_type;
    if (property.bathroom_number) {
      stats += &amp;#x27;, &amp;#x27; + property.bathroom_number + &amp;#x27; &amp;#x27; + (property.bathroom_number &amp;gt; 1
        ? &amp;#x27;bathrooms&amp;#x27; : &amp;#x27;bathroom&amp;#x27;);
    }
 
    var price = property.price_formatted.split(&amp;#x27; &amp;#x27;)[0];
 
    return (
      &amp;lt;View style={styles.container}&amp;gt;
        &amp;lt;Image style={styles.image}
            source={{uri: property.img_url}} /&amp;gt;
        &amp;lt;View style={styles.heading}&amp;gt;
          &amp;lt;Text style={styles.price}&amp;gt;£{price}&amp;lt;/Text&amp;gt;
          &amp;lt;Text style={styles.title}&amp;gt;{property.title}&amp;lt;/Text&amp;gt;
          &amp;lt;View style={styles.separator}/&amp;gt;
        &amp;lt;/View&amp;gt;
        &amp;lt;Text style={styles.description}&amp;gt;{stats}&amp;lt;/Text&amp;gt;
        &amp;lt;Text style={styles.description}&amp;gt;{property.summary}&amp;lt;/Text&amp;gt;
      &amp;lt;/View&amp;gt;
    );
  }
}
&lt;/pre&gt;
  &lt;p&gt;Часто случается так, что API возвращает данные низкого качества и с пропущенными полями. Потому первая часть &lt;strong&gt;render()&lt;/strong&gt; проводит обработку данных для частичного улучшения их качества.&lt;/p&gt;
  &lt;p&gt; Остальная его часть весьма очевидна: это функция неизменяемого состояния данного компонента.&lt;/p&gt;
  &lt;p&gt; Теперь добавим экспорт в конец файла:&lt;/p&gt;
  &lt;pre&gt;module.exports = PropertyView;
&lt;/pre&gt;
  &lt;p&gt;Вернитесь к &lt;strong&gt;SearchResults.js&lt;/strong&gt; и добавьте выражение &lt;strong&gt;require&lt;/strong&gt; в начало файла, сразу после строки React &lt;strong&gt;require&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre&gt;var PropertyView = require(&amp;#x27;./PropertyView&amp;#x27;);
&lt;/pre&gt;
  &lt;p&gt;Затем обновите &lt;strong&gt;rowPressed()&lt;/strong&gt;, чтобы перемещаться по &lt;strong&gt;PropertyView&lt;/strong&gt;:&lt;/p&gt;
  &lt;pre&gt;rowPressed(propertyGuid) {
  var property = this.props.listings.filter(prop =&amp;gt; prop.guid === propertyGuid)[0];
 
  this.props.navigator.push({
    title: &amp;quot;Property&amp;quot;,
    component: PropertyView,
    passProps: {property: property}
  });
}
&lt;/pre&gt;
  &lt;p&gt;Порядок действий вам знаком: сохраняем, возвращаемся в симулятор и нажимаем Cmd+R. Теперь можно выполнить поиск, выбрать любой объект и перейти к просмотру информации о нем:&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://habrastorage.org/files/607/1f4/a4f/6071f4a4fd3241be8893d7c8f53ff639.png&quot; width=&quot;281&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Эх, вот что я называю доступным жильем!&lt;/p&gt;
  &lt;p&gt; Приложение почти готово, осталось только добавить опцию поиска по геолокации. &lt;/p&gt;
  &lt;p&gt; &lt;strong&gt;Реализуем поиск по местоположению&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt; Откройте в Xcode файл Info.plist и добавьте напротив &lt;strong&gt;NSLocationWhenInUseUsageDescription&lt;/strong&gt; следующее значение:&lt;/p&gt;
  &lt;pre&gt;PropertyFinder would like to use your location to find nearby properties – 
&lt;/pre&gt;
  &lt;p&gt;Вот как будет выглядеть ваш plist-файл после добавления нового значения:&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://habrastorage.org/files/2ff/bd1/e40/2ffbd1e4076b4aa2abbb97a0af530538.png&quot; width=&quot;480&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;Это информация, которую приложение будет отображать пользователям при попытке запросить их местоположение.&lt;/p&gt;
  &lt;p&gt; Откройте SearchPage.js, перейдите к компоненту &lt;strong&gt;TouchableHighlight&lt;/strong&gt;, отвечающему за отображение кнопки ‘Location’, и добавьте это значение:&lt;/p&gt;
  &lt;pre&gt;onPress={this.onLocationPressed.bind(this)}
&lt;/pre&gt;
  &lt;p&gt;По нажатию кнопки вызывается метод &lt;strong&gt;onLocationPressed&lt;/strong&gt; (мы сейчас его добавим).&lt;/p&gt;
  &lt;p&gt; Вставьте внутрь класса &lt;strong&gt;SearchPage&lt;/strong&gt; следующий код:&lt;/p&gt;
  &lt;pre&gt;onLocationPressed() {
  navigator.geolocation.getCurrentPosition(
    location =&amp;gt; {
      var search = location.coords.latitude + &amp;#x27;,&amp;#x27; + location.coords.longitude;
      this.setState({ searchString: search });
      var query = urlForQueryAndPage(&amp;#x27;centre_point&amp;#x27;, search, 1);
      this._executeQuery(query);
    },
    error =&amp;gt; {
      this.setState({
        message: &amp;#x27;There was a problem with obtaining your location: &amp;#x27; + error
      });
    });
}
&lt;/pre&gt;
  &lt;p&gt;Данные о текущем местоположении берутся с помощью &lt;strong&gt;navigator.geolocation&lt;/strong&gt;. Это &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/Using_geolocation&quot; target=&quot;_blank&quot;&gt;интерфейс Web API&lt;/a&gt;, потому он должен быть понятен каждому, кто имел дело с браузерными сервисами определения геолокации. React Native предоставляет собственную реализацию данного API, используя нативные средства iOS.&lt;/p&gt;
  &lt;p&gt; В случае успешного определения текущего местоположения будет вызвана первая стрелочная функция. Она отправит запрос в Nestoria. Если же что-то пойдет не так, отобразится стандартное сообщение.&lt;/p&gt;
  &lt;p&gt; Так как мы редактировали plist, потребуется перезапустить приложение, чтобы увидеть изменения. На этот раз, увы, без Cmd+R. Остановите приложение в Xcode и выполните его повторную сборку. Затем запустите проект.&lt;/p&gt;
  &lt;p&gt; Прежде чем использовать поиск по геолокации, стоит убедиться, что база данных Nestoria содержит информацию о вашем регионе. Выберите в меню симулятора &lt;strong&gt;Debug\Location\Custom Location …&lt;/strong&gt; и введите широту с долготой: к примеру, 55.02 и -1.42 соответственно. Это координаты одного живописного городка на побережье северной части Англии, откуда я родом.&lt;/p&gt;
  &lt;p&gt; Теперь нажмите кнопку Location, разрешите приложению определять местоположение и смотрите результат.&lt;/p&gt;
  &lt;figure class=&quot;m_original&quot;&gt;
    &lt;img src=&quot;https://habrastorage.org/files/56f/dfb/810/56fdfb8102ab4433804417f0ada4270a.png&quot; width=&quot;647&quot; /&gt;
  &lt;/figure&gt;
  &lt;p&gt;&lt;strong&gt;Примечание от Рэя&lt;/strong&gt;: Поиск по местоположению сработал не у всех. Как правило, возникала ошибка доступа, несмотря на то, что определение местоположения было разрешено. Мы пока не до конца разобрались с этой ситуацией. Возможно, это проблема самого React Native. Если кому-либо удалось исправить эту ошибку, пожалуйста, напишите нам.&lt;/p&gt;

</content></entry></feed>