Пишем полноценное приложение на React с нуля за час

В этой статье вы познакомитесь с React — библиотекой для создания пользовательских интерфейсов. React появился в 2013 году и достаточно быстро стал популярным среди разработчиков. Сегодня в работе над веб-приложениями его используют Facebook, Instagram, Trello, AirBnb, PayPal. С помощью этой статьи мы сможем написать приложение прогноза погоды: от установки с помощью create-react-app (проект на GitHub) до подключения API и стилей bootswatch.

Прим. перев. Если вы начинаете изучение React, вам также стоит прочитать наш материал, в котором разработчик делится советами по использованию этой библиотеки.

Этот материал был написан для воркшопа Open Source Dev Garage, прошедшего в рамках конференции разработчиков F8 2017. Чтобы лучше разобраться в том, как написать это приложение, посмотрите 48-минутное видео или следуйте письменным инструкциям в этом руководстве.

Просмотрев семинар или изучив руководство, вы создадите простое приложение прогноза погоды:

React

Итак, приступим.

Создайте ваше первое приложение

Прежде всего вам понадобится node.js и редактор кода, например, Atom.

Откроем терминал и установим create-react-app:

npm install -g create-react-app

Примечание: Пользователям Linux или MacOS, возможно, потребуется дополнительно ввести команду sudo перед npm install -g.

Начнем создавать наше приложение прогноза погоды:

create-react-app weather

Данной командой мы установим набор инструментов, которые помогут создать наше React-приложение. По завершении установки мы сможем запустить приложение командами:

cd weather
npm start

Новое приложение автоматически откроется в браузере!

React

Свойства и компоненты

Давайте взглянем на приложение, которое create-react-app создал автоматически. В редакторе кода откроем weather/src/App.js:

class App extends Component {
  render() {
    return (
      <div className="App">
        <div className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h2>Welcome to React</h2>
        </div>
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
      </div>
    );
  }
}

Наше приложение состоит из одного компонента, где функция render() является его главной составляющей. Напишите какой-нибудь текст, сохраните изменения и посмотрите, как приложение автоматически применит их!

Теперь создадим новый компонент WeatherDisplay. Так как функция render() — это «сердце» компонента, то именно она определяет, что будет отображено. Для начала создадим тег с каким-нибудь текстом внутри:

class WeatherDisplay extends Component {
  render() {
    return (
      <h1>Displaying some Weather!</h1>
    );
  }
}

Изменим компонент App, чтобы отобразить наш WeatherDisplay:

class App extends Component {
  render() {
    return (
      <div className="App">
        <WeatherDisplay zip={"12345"} />
      </div>
    );
  }
}

Как видите, мы передали данные, которые обозначили переменной zip, в компонент WeatherDisplay. Они называются свойствами (props). Мы можем модифицировать наш компонент для отображения передаваемых данных:

class WeatherDisplay extends Component {
  render() {
    return (
      <h1>Displaying weather for city {this.props.zip}</h1>
    );
  }
}

Где-нибудь в начале файла добавим несколько городов, для которых мы хотели бы отобразить погоду:

const PLACES = [
  { name: "Palo Alto", zip: "94303" },
  { name: "San Jose", zip: "94088" },
  { name: "Santa Cruz", zip: "95062" },
  { name: "Honolulu", zip: "96803" }
];

Обновим render() в компоненте App, в котором, перебирая массив PLACES, создадим тег button для каждого города:

return (
  <div className="App">
    <WeatherDisplay zip={"12345"} />
    {PLACES.map((place, index) => (
      <button
        key={index}
        onClick={() => {
          console.log('Clicked index '+index);
        }}
      >
          {place.name}
      </button>
    ))}
  </div>
);

Из массива данных мы создадим набор элементов button и назначим свойство key для каждого, чтобы React знал последовательность элементов в массиве.

Здесь также есть обработчик событий onClick, который при нажатии будет выводить сообщение в консоль браузера. Открыв панель разработчика в браузере, вы можете увидеть логи событий. Ваше приложение должно выглядеть так:

React

На этом этапе файл App.js должен выглядеть так.

Состояние

Мы хотим, чтобы в приложении была возможность переключаться между местами, поэтому мы можем использовать состояние (state) для хранения данных в компоненте App.

Сначала давайте добавим функцию-конструктор, в которой будет использоваться super(), а затем установим начальное состояние this.state:

constructor() {
  super();
  this.state = {
    activePlace: 0,
  };
}

Функция render() может брать данные из this.state при составлении пользовательского интерфейса. Для этого мы можем использовать метод setState компонента React, который меняет состояние и перезапускает функцию render(), чтобы изменить пользовательский интерфейс.

Применим this.state и this.setState в нашем компоненте App:

class App extends Component {
  constructor() {
    super();
    this.state = {
      activePlace: 0,
    };
  }
  render() {
    const activePlace = this.state.activePlace;
    return (
      <div className="App">
        {PLACES.map((place, index) => (
          <button
            key={index}
            onClick={() => {
              this.setState({ activePlace: index });
            }}
          >
              {place.name}
          </button>
        ))}
        <WeatherDisplay
          key={activePlace}
          zip={PLACES[activePlace].zip}
        />
      </div>
    );
  }
}

React

На этом этапе файл App.js должен выглядеть так.

Жизненный цикл компонентов и выборка данных

Иногда нам нужно добавить императивный код (React-код обычно декларативен), который вызывается в определенное время жизни компонента. Методы жизненного цикла позволяют нам написать дополнительный код как раз для таких случаев.

В этом примере мы хотим вызвать API, когда компонент загрузится на экране, для этого добавим код в componentDidMount. Обновим компонент WeatherDisplay:

class WeatherDisplay extends Component {
  constructor() {
    super();
    this.state = {
      weatherData: null
    };
  }
  componentDidMount() {
    const zip = this.props.zip;
    const URL = "http://api.openweathermap.org/data/2.5/weather?q=" +
      zip +
      "&appid=b1b35bba8b434a28a0be2a3e1071ae5b&units=imperial";
    fetch(URL).then(res => res.json()).then(json => {
      this.setState({ weatherData: json });
    });
  }
  render() {
    const weatherData = this.state.weatherData;
    if (!weatherData) return <div>Loading</div>;
    return <div>{JSON.stringify(weatherData)}</div>;
  }
}

Улучшим вывод render() для красивого вывода данных:

const weather = weatherData.weather[0];
const iconUrl = "http://openweathermap.org/img/w/" + weather.icon + ".png";
return (
  <div>
    <h1>
      {weather.main} in {weatherData.name}
      <img src={iconUrl} alt={weatherData.description} />
    </h1>
    <p>Current: {weatherData.main.temp}°</p>
    <p>High: {weatherData.main.temp_max}°</p>
    <p>Low: {weatherData.main.temp_min}°</p>
    <p>Wind Speed: {weatherData.wind.speed} mi/hr</p>
  </div>
);

React

На этом этапе файл App.js должен выглядеть так.

Установка компонентов

Наше приложение всё еще выглядит не очень красиво. Можно исправить это, добавив className (из стилей CSS) в свойства div или установив соответствующую библиотеку с помощью npm.

Bootstrap — популярный набор инструментов для стилизации пользовательского интерфейса в HTML и CSS. Установим его вместе с react-bootstrap, который предоставляет компоненты React для bootstrap:

npm install --save bootstrap react-bootstrap

Импортируем стили из bootstrap в начале файла:

import "bootstrap/dist/css/bootstrap.css";

Далее импортируем из react-bootstrap компоненты, которые мы хотим использовать. Их можно найти на сайте react-bootstrap:

import { Navbar, NavItem, Nav, Grid, Row, Col } from "react-bootstrap";

Заменим теги в компоненте App, чтобы вывести компоненты bootstrap:

<div>
  <Navbar>
    <Navbar.Header>
      <Navbar.Brand>
        React Simple Weather App
      </Navbar.Brand>
    </Navbar.Header>
  </Navbar>
  <Grid>
    <Row>
      <Col md={4} sm={4}>
        <h3>Select a city</h3>
        <Nav
          bsStyle="pills"
          stacked
          activeKey={activePlace}
          onSelect={index => {
            this.setState({ activePlace: index });
          }}
        >
          {PLACES.map((place, index) => (
            <NavItem key={index} eventKey={index}>{place.name}</NavItem>
          ))}
        </Nav>
      </Col>
      <Col md={8} sm={8}>
        <WeatherDisplay key={activePlace} zip={PLACES[activePlace].zip} />
      </Col>
    </Row>
  </Grid>
</div>

React

Теперь наше приложение выглядит привлекательнее, но будет здорово, если мы добавим что-то от себя. Для этого установим bootswatch:

npm install --save bootswatch

Выберите подходящее оформление на сайте bootswatch и установите его, заменив bootstrap. В нашем примере мы используем тему journal:

import "bootswatch/journal/bootstrap.css";

Окончательный вид нашего приложения:

React

Окончательный вариант App.js.

Развертывание (дополнительный материал)

Прежде всего опубликуйте ваш код на Github, затем перейдите в ваш репозиторий и откройте файл ReadMe, в котором вы найдете инструкцию по развертыванию приложения на различных популярных сервисах.

Одним из таких сервисов является Netlify, особенно в случае, когда вы хотите использовать механизм “непрерывного развертывания”.

Полезные материалы для изучения React и дальнейшей работы с ним

  • React Native: используйте React для создания мобильных приложений.
  • Redux: инструмент для управления данными в больших приложениях.
  • Relay: библиотека для связи компонентов React и данных GraphQL.
  • Jest: фреймфорк для тестирования JS-кода.
  • Flow: инструмент для статической проверки типов.

Перевод статьи «Intro To React Workshop»