Гостевая запись Пола Пагнана, инженера @ KentandLime

Изучите основы ReactJS, создав в этом руководстве простое приложение для мгновенного чата в стиле Facebook Messenger.

ReactJs - одна из самых популярных технологий в сети сегодня благодаря своей простоте и скорости. Важно отметить, что ReactJS - это не фреймворк, это библиотека. Таким образом, несправедливо сравнивать его с другими технологиями, такими как AngularJs или Ember. Веб-фреймворки, такие как AngularJs, предоставляют разработчику большинство инструментов, необходимых для разработки комплексного интерфейсного приложения, такого как встроенные функции для маршрутизации, проверки форм, запросов HTTP-сервисов и многое другое. Однако библиотека ReactJs сосредоточена исключительно на уровне представления и оставляет разработчику возможность управлять остальными сложностями. Это дает разработчику гораздо больше контроля над реализацией различных функций.

Это руководство проведет читателя через разработку простого приложения для мгновенного чата, похожего на Facebook Messenger, созданного с использованием ReactJs и Socket.io. В этом руководстве предполагается, что у вас уже есть базовые представления о JavaScript, фреймворке ReactJS и синтаксисе ES6. Что вообще такое ES6? Ну, есть шесть разновидностей JavaScript,

Если вы ничего не знаете об этих двух, я предлагаю вам прекратить читать здесь и ознакомиться со следующими статьями:

TL;DR

Если вы сразу после законченного, прокомментированного исходного кода, тогда проверьте репозиторий Github здесь: response-instant-chat

Готовый продукт выглядит так:

Немного обо мне

Меня зовут Пол Паньян, я инженер-программист в Kent and Lime. Kent and Lime - первый технологический стартап из Сиднея, стремящийся изменить то, как мужчины делают покупки в Интернете. Мы отправим вам коробку с профессиональной одеждой, соответствующей вашему размеру, стилю и бюджету. Вы можете проверить нас на https://kentandlime.com.au.

Наша команда инженеров всегда использует передовые технологии для решения сложных бизнес-задач. Наш технологический стек состоит в основном из ES6 Javascript. Javascript обеспечивает чрезвычайно быструю разработку, которая соответствует передовому и динамичному характеру бизнеса. Вероятно, это причина того, что библиотеки javascript, такие как ReactJs, набирают огромную популярность не только в стартапах, но и в более крупных организациях.

P.s. Мы набираем сотрудников, не стесняйтесь связаться со мной в LinkedIn, если вам интересно. Мой профиль находится здесь

Начиная

Для начала я рекомендую загрузить стартовый комплект для этого урока. Он содержит скелетную версию приложения, так что вам не придется делать какие-либо скучные вещи разработчика, чтобы начать работу. В стартовый комплект также входят все таблицы стилей, которые мы будем использовать в этом уроке. Вы можете скачать стартовый комплект здесь: React-Instant-Chat-tutorial.

После того, как вы его загрузили, убедитесь, что вы правильно установили зависимости npm, запустив: npm install. После успешного завершения вы можете запустить npm start, чтобы запустить сервер.

Я также создал простой API чата, к которому мы будем подключаться из нашего приложения ReactJs. Я не буду рассказывать, как это было построено, но не стесняйтесь взглянуть на исходный код, чтобы попытаться понять это. Вот как его запустить:

1. Download the code from https://github.com/kentandlime/simple-chat-api
  2. cd into the directory
  3. run 'npm install'
  4. run 'npm run compile'
  5. run 'npm start'

Файловая структура

Каркас стартового набора имеет следующую файловую структуру:

- src
    - components
      - App.js
        (we will show a simple login screen here)
      - ChatApp.js
        (this is where the main app is shown)
      - ChatInput.js
        (the input box where the user enters their message)
      - Messages.js
        (shows a list of the messages which have been sent and received)
      - Message.js
        (shows an individual message)

1. Экран входа в систему

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

Во-первых, давайте начнем с метода рендеринга внутри App.js. Сначала мы начнем с визуализации простой формы входа в систему.

render() {
    return (
      <form onSubmit={this.usernameSubmitHandler} className="username-container">
        <h1>React Instant Chat</h1>
        <div>
          <input
            type="text"
            onChange={this.usernameChangeHandler}
            placeholder="Enter a username..."
            required />
        </div>
        <input type="submit" value="Submit" />
      </form>
    );
  }

Обратите внимание, что здесь мы ссылаемся на два обработчика событий. Один для события onChange в поле ввода и один для события onSubmit формы.

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

Эти два обработчика событий следующие:

usernameChangeHandler(event) {
    this.setState({ username: event.target.value });
  }
  usernameSubmitHandler(event) {
    event.preventDefault();
    this.setState({ submitted: true, username: this.state.username });
  }

ПРИМЕЧАНИЕ. ReactJs не связывает автоматически ключевое слово this с обработчиками событий. Таким образом, если мы хотим вызвать какой-либо метод для «this» (в этом примере мы вызываем this.setState), нам нужно сначала привязать ключевое слово «this» к методу в конструкторе компонента.

конструктор (реквизиты) {супер (реквизиты); // устанавливаем начальное состояние приложения this.state = {username: ‘’}; // привязываем ключевое слово this к обработчикам событий this.usernameChangeHandler = this.usernameChangeHandler.bind (this); this.usernameSubmitHandler = this.usernameSubmitHandler.bind (это); }

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

render() {
  if (this.state.submitted) {
      // Form was submitted, now show the main App
      return (
        <ChatApp username={this.state.username} />
      );
    }
  ...

Ваш окончательный файл App.js должен выглядеть так, как тот, что находится здесь.

2. Главный экран приложения

Теперь, когда мы разрешили пользователю войти в комнату чата, мы хотим отобразить главное приложение. Основное приложение состоит из двух основных компонентов: секции пользовательского ввода и секции сообщений.

Опять же, давайте начнем с метода рендеринга.

render() {
    return (
      <div className="container">
        <h3>React Chat App</h3>
        <Messages messages={this.state.messages} />
        <ChatInput onSend={this.sendHandler} />
      </div>
    );
  }

Глядя на это, мы можем сделать два вывода.

  • 1) Компонент сообщения должен принимать массив сообщений. Таким образом, мы должны создать способ перевести эти сообщения в состояние (мы сделаем это позже)
  • 2) ChatInput генерирует событие onSend. В результате мы должны создать обработчик событий, который принимает это событие, добавляет сообщение в состояние и отправляет его на сервер.

Этим мы займемся позже. Сначала давайте создадим компоненты Messages и ChatInput.

3. Просмотр сообщений

Представление сообщения примет массив объектов сообщения через свойства компонента. Мы передаем массив через свойства (как показано в методе рендеринга ChatApp) и получаем к ним доступ внутри компонента Messages через this.props.messages.

По сути, цель компонента «Сообщения» - перебрать каждое сообщение и создать отдельный компонент «Сообщение». Компонент "Сообщение" отобразит фактическое сообщение.

Итак, метод рендеринга должен быть следующим:

render() {
    // Loop through all the messages in the state and create a Message component
    const messages = this.props.messages.map((message, i) => {
        return (
          <Message
            key={i}
            username={message.username}
            message={message.message}
            fromMe={message.fromMe} />
        );
      });
    return (
      <div className='messages' id='messageList'>
        { messages }
      </div>
    );
  }
}

Давайте проанализируем, что делает этот метод. Сначала начнем с получения массива сообщений из свойств, затем мы перебираем его, используя функцию карты. Карта - это новая функция массива ES6, о которой вы можете прочитать здесь. Для каждого сообщения в массиве мы создаем компонент Message. Компонент сообщения принимает три свойства.

  • 1) ключ - ключ является опорой React, которая сообщает рендереру индекс текущего компонента в цикле. Помните, что движок рендеринга React отображает изменения только с помощью системы различий. Таким образом, свойство key - это способ для React определить, какой компонент нужно повторно отрисовать, в зависимости от того, какой элемент в массиве изменился.
  • 2) username - имя пользователя, отправившего сообщение
  • 3) message - собственно тело сообщения
  • 4) fromMe - логическое значение, которое определяет, было ли сообщение отправлено от текущего пользователя (мы показываем разные стили на основе этого, т.е. правую или левую сторону экрана)

Мы сохраняем результат этого цикла внутри локальной переменной, чтобы наш код был чистым.

Затем мы помещаем эту переменную в контейнер div и возвращаем ее.

Наконец, компонент сообщений должен автоматически прокручиваться вниз при получении нового сообщения. Мы можем добиться такого поведения, используя метод жизненного цикла компонента React, называемыйcomponentDidUpdate (). Как вы, наверное, догадались, этот метод вызывается при изменении свойств компонента. Нам доступно множество различных методов жизненного цикла; Вы можете узнать об этом подробнее здесь.

Для прокрутки просмотра сообщений мы можем использовать простой javascript, например:

componentDidUpdate() {
    // get the messagelist container and set the scrollTop to the height of the container
    const objDiv = document.getElementById('messageList');
    objDiv.scrollTop = objDiv.scrollHeight;
  }

Ваш последний компонент "Сообщения" должен выглядеть так, как "здесь"

4. Сообщение

Теперь, когда мы создали представление «Сообщения» для просмотра всех сообщений, нам нужен способ отображения одного сообщения. Мы создаем очень простой компонент под названием Message, который отображает содержимое свойств, которые мы передали через компонент Messages. Метод рендеринга должен быть следующим:

render() {
    // Was the message sent by the current user. If so, add a css class
    const fromMe = this.props.fromMe ? 'from-me' : '';
    return (
      <div className={`message ${fromMe}`}>
        <div className='username'>
          { this.props.username }
        </div>
        <div className='message-body'>
          { this.props.message }
        </div>
      </div>
    );
  }

Обратите внимание, что мы используем свойство fromMe для условного добавления класса CSS в контейнер сообщения.

5. Вход в чат

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

Как всегда, начнем с метода рендеринга.

render() {
    return (
      <form className="chat-input" onSubmit={this.submitHandler}>
        <input type="text"
          onChange={this.textChangeHandler}
          value={this.state.chatInput}
          placeholder="Write a message..."
          required />
      </form>
    );
  }

Метод рендеринга здесь прост. Создаем форму и поле ввода. Когда форма отправляется (пользователь нажимает клавишу ввода внутри поля ввода), вызывается submitHandler. Когда мы изменяем текст в поле ввода, вызывается textChangeHandler, и значение this.state.chatInput привязывается к полю ввода. Мы привязываем это значение обратно к полю ввода, чтобы мы могли легко очистить поле после отправки формы. Давайте посмотрим на эти обработчики событий:

1) Обработчик изменения текста

Обработчик изменения текста должен принимать ввод из текстового поля и переводить его в состояние компонента, чтобы мы могли использовать это значение позже. Обработчик должен выглядеть так:

textChangeHandler(event)  {
    this.setState({ chatInput: event.target.value });
  }

2) Отправить обработчик

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

submitHandler(event) {
    // Stop the form from refreshing the page on submit
    event.preventDefault();
    // Call the onSend callback with the chatInput message
    this.props.onSend(this.state.chatInput);
    // Clear the input box
    this.setState({ chatInput: '' });
  }

Разберем этот метод подробнее.

Во-первых, event.preventDefault () не позволяет встроенной HTML-форме обновлять страницу при ее отправке.

Во-вторых, мы отправляем событие родительскому компоненту со значением chatInput. Вы заметите, что в родительском компоненте (ChatApp.js) мы передаем свойство onSend компоненту ChatInput. В этом случае свойство onSend является функцией. Фактическая функция onSend находится внутри родительского компонента, и мы передаем ссылку на эту функцию дочернему элементу через реквизиты. Дочерний элемент может вызвать эту ссылку на функцию, и он будет запускать любой код, определенный в родительском элементе. Эта функция в настоящее время не существует, но мы создадим ее в части 6.

Наконец, как только мы отправили событие родительскому объекту, мы хотим очистить ввод пользователя. Мы делаем это, просто устанавливая chatInput внутри состояния на '' (помните, что в методе рендеринга мы привязали this.state.chatInput к значению поля ‹input /›. Это позволяет нам обновлять значение поля, просто установив связанное с ним поле состояния).

Как и раньше, нам нужно привязать это к нашим обработчикам событий. Мы также должны установить начальное состояние chatInput, чтобы оно не было неопределенным при загрузке компонента.

constructor(props) {
    super(props);
    // Set initial state of the chatInput so that it is not undefined
    this.state = { chatInput: '' };
    // React ES6 does not bind 'this' to event handlers by default
    this.submitHandler = this.submitHandler.bind(this);
    this.textChangeHandler = this.textChangeHandler.bind(this);
  }

Ваш последний компонент должен выглядеть так, как здесь

6. Связать все вместе

Теперь самое интересное - связать все вместе и заставить работать!

Последнее, что осталось сделать, это подключить api чата к нашему приложению.

ПРИМЕЧАНИЕ: Убедитесь, что на этом этапе у вас запущен simple-chat-api. Чтобы запустить его, скачайте его и прочтите инструкции в README репо

Я также рекомендую проверить, как работает socket.IO, прежде чем продолжить, это очень просто. Узнать больше здесь

Мы осуществляем всю связь с сервером из компонента ChatApp. Во-первых, нам нужно подключиться к нашему серверу socket.io. В конструкторе ChatApp мы должны добавить следующее:

constructor(props) {
    super(props);
    // set the initial state of messages so that it is not undefined on load
    this.state = { messages: [] };
    // Connect to the server
    this.socket = io(config.api).connect();
    ...

Эта строка кода инициализирует библиотеку socket.IO путем передачи адреса сервера. Мы определяем адрес сервера внутри файла конфигурации, чтобы при необходимости можно было легко его изменить (файл конфигурации находится в src / config / index.js).

Затем мы должны создать обработчик onSend для отправки сообщения на сервер, когда пользователь отправляет сообщение. Помните, как раньше мы отправляли onSend из компонента ChatInput. Здесь мы определяем, что на самом деле делает это событие onSend. Внутри ChatApp мы должны определить следующую функцию:

sendHandler (сообщение) {
const messageObject = {
имя пользователя: this.props.username,
message
};

// Отправляем сообщение на сервер
this.socket.emit (‘client: message’, messageObject);

messageObject.fromMe = true;
this.addMessage (messageObject);
}

// Помните, что мы связали эту функцию на шаге 2 этого руководства
// Вы увидите это в методе рендеринга ChatApp.js ‹ChatInput onSend = {this.sendHandler} /›

Давайте разберемся с этим методом.

  • 1) Мы создаем объект messageObject, который можно легко использовать повторно. Объект содержит имя пользователя и фактическое сообщение, которое было передано из компонента ChatInput через параметры функции (помните, когда мы вызывали this.props.onSend (this.state.chatInput) из дочернего компонента).
  • 2) Далее мы фактически отправляем сообщение. Благодаря магии socket.io эта строка кода отправит сообщение на сервер. Так легко и просто, правда !?
  • 3) Текущий пользователь отправляет сообщение, поэтому мы хотим добавить флаг fromMe, чтобы наше сообщение правильно отображалось справа в окне просмотра сообщений.
  • 4) Мы вызываем функцию addMessage, чтобы добавить наш метод в состояние.

ПРИМЕЧАНИЕ. Не забудьте привязать это к sendHandler.

Теперь давайте определим функцию addMessage:

addMessage(message) {
    // Append the message to the component state
    const messages = this.state.messages;
    messages.push(message);
    this.setState({ messages });
  }

Это очень простая функция, которая берет объект сообщения и добавляет его в состояние.

Теперь, когда состояние обновлено, автоматически запускается метод рендеринга ChatApp, и новое сообщение передается в компонент Messages. Запомните эту строку в методе рендеринга ‹Messages messages = {this.state.messages} /›.

Самый последний шаг - определить, что происходит, когда мы получаем сообщение от сервера; мы тоже хотим добавить его в состояние, не так ли? Давай сделаем это сейчас. Добавьте это в нижнюю часть конструктора внутри ChatApp:

constructor(props) {
    ...
    // Listen for messages from the server
    this.socket.on('server:message', message => {
      this.addMessage(message);
    });
  }

Благодаря магии socket.io этот обратный вызов будет запускаться каждый раз, когда приходит сообщение от другого человека в чате. Когда мы получаем сообщение, все, что нам нужно сделать, это добавить его в состояние, вызвав функцию addMessage, которую мы определили ранее.

Ваш окончательный файл ChatApp.js должен выглядеть так, как тот, что находится здесь.

Поздравляем, вы успешно создали приложение для мгновенного чата React. Приятного общения!

Академия Coder Factory: познакомьтесь с первым и единственным аккредитованным учебным курсом по ускоренному программированию в Австралии! Наш иммерсивный курс помогает студентам приобрести востребованные навыки посредством практического обучения на основе проектов, проводимого отраслевыми экспертами в течение 23 недель. Станьте полноценным разработчиком всего за шесть месяцев.

Сейчас набор отечественных и иностранных студентов в Сиднее и Мельбурне! Учись сейчас, плати потом!

Coder Factory теперь предлагает семинары по цифровому лидерству и технологиям для сотрудников компаний, которым нужны технологии, инновации и цифровая грамотность. Учебные занятия представляют собой мини-хакатоны, где сотрудники работают над тем, чтобы использовать технологии для решения реальных проблем в своей компании.

Узнайте больше о наших семинарах по корпоративному обучению.

Вы женщина, интересующаяся программированием? Ознакомьтесь с нашими стипендиями для женщин-исследователей!