В этой статье я покажу вам самый простой способ написать, используя React, приложение для общения. Серверного кода здесь не будет совсем, а его роль выполнит Chatkit API.
Предполагается, что вы знаете основы JavaScript и что до этого сталкивались с React JS. Кроме этого никаких требований нет.
Если вы будете следовать этому уроку, то получите собственное чат-приложение, работу над которым при желании можете продолжить позднее.
Начнем!
Шаг 1: Разбивка интерфейса на компоненты
React JS строится вокруг компонентов, поэтому для начала нужно разложить интерфейс на его элементы. Сначала отрисуем прямоугольник вокруг приложения. Это будет корневым компонентом, в котором будут находиться все остальные. Назовем его App
:
После того как мы определили корневой компонент, нужно задаться вопросом: каковы его дочерние элементы? В нашем случае будет всего 3 таких элемента, которые мы назовем следующим образом:
- Title;
- MessagesList;
- SendMessageFrom.
Создадим по прямоугольнику для каждого из этих элементов:
Благодаря этому мы теперь отдаем себе отчет о различных компонентах и архитектуре приложения.
Можно было бы вновь спросить себя, какие дочерние элементы есть у вышеперечисленных компонентов. Тогда интерфейс мы бы разложили на большее количество компонентов, например, каждое сообщение было бы отдельным элементом. Но ради простоты структуры остановимся на текущей.
Шаг 2: Настройка кодовой базы
Разберемся с нашим хранилищем. Будем использовать простейшую структуру: файл index.html, который ссылается на файл JavaScript и таблицу стилей. Также импортируем Chatkit SDK и Babel, которые необходимы для трансформации JSX:
Вот тут вы можете найти готовый код. Его можно использовать каждый раз, когда вы «заходите в тупик» и не понимаете, что происходит в статье. Или же скачать исходники и развернуть у себя на локальной машине (архив также добавил и в конце статьи).
Шаг 3: Создание корневого компонента
Настроив все элементы, начнем писать код на React внутри файла index.js.
Первым будет главный компонент App
- единственный «умный» компонент, который будет заниматься обработкой информации и связываться с API. Его базовый вид (без добавления логики):
class App extends React.Component {
render() {
return (
<div className="app">
<Title />
<MessageList />
<SendMessageForm />
</div>
)
}
}
Как вы могли заметить, он попросту рендерит 3 дочерних элемента: <Title>
, <MessageList>
, <SendMessageForm>
. Однако мы все усложним: данные о сообщениях будут храниться в атрибуте state
компонента App
. Так мы сможем получать доступ к сообщениям через this.state.messages
и передавать их другим элементам.
Сначала мы будем использовать фиктивные данные, чтобы понимать, как работает приложение. Затем мы заменим эту информацию на настоящие данные от Chatkit API. Введем переменную DUMMY_DATA
:
const DUMMY_DATA = [
{
senderId: "perborgen",
text: "who'll win?"
},
{
senderId: "janedoe",
text: "who'll win?"
}
]
После этого добавим данные в state
компонента App
и передадим их в MessageList
. Здесь мы инициализируем state
в constructor
и передаем this.state.messages
MessageList
.
class App extends React.Component {
constructor() {
super()
this.state = {
messages: DUMMY_DATA
}
}
render() {
return (
<div className="app">
<MessageList messages={this.state.messages} />
<SendMessageForm />
</div>
)
}
}
Внимание: в конструкторе мы вызываем super(). Это нужно делать, чтобы создать компонент, запоминающий текущее состояние.
Шаг 4: Рендеринг сообщений
Давайте посмотрим, как провести рендеринг сообщений в компоненте MessagesList
. Вот как это выглядит:
class MessageList extends React.Component {
render() {
return (
<ul className="message-list">
{this.props.messages.map(message => {
return (
<li key={message.id}>
<div>
{message.senderId}
</div>
<div>
{message.text}
</div>
</li>
)
})}
</ul>
)
}
}
Этот компонент называется «глупым». У него есть всего одно свойство - messages
, в котором содержится массив объектов. Далее мы просто рендерим атрибуты text
и senderId
из объектов.
Когда в компонент перейдет информация, выйдет следующее:
Теперь у нас есть основа приложения, и мы также можем отрисовывать сообщения. Отличная работа!
Теперь заменим фиктивные данные на настоящие!
Шаг 5: Получение API-ключа из Chatkit
Чтобы получить сообщения, нужно подключиться к Chatkit API, а, чтобы это сделать, необходимо получить ключ для работы с API.
Хочу приободрить вас, чтобы вы продолжили следовать этому уроку и создали собственный мессенджер. Можете использовать готовый код на Scrimba, чтобы протестировать собственные ключи API.
Сначала зарегистрируйтесь здесь. Как только вы это сделаете, то увидите свой личный кабинет. Здесь нужно создать новый образец Chatkit. Создаем и называем как угодно:
Вас перенаправят к вашему образцу. Здесь нужно скопировать 4 значения:
- Instance Locator;
- Test Token Provider;
- Room id;
- Username.
Начнем с Instance Locator:
Если прокрутить страницу ниже, то можно обнаружить Test Token Provider:
Дальше необходимо создать User и Room, что делается на той же странице:
Обратите внимание, что сначала создается User, а затем - Room, что дает доступ к id комнаты. Мы получили 4 нужных значения. Отлично! Однако до того, как вернуться к кодовой базе, отправьте сообщение вручную при помощи Chatkit, ведь это поможет нам в следующем шаге.
Вот как это сделать:
Это нужно для того, чтобы в следующем шаге было что рендерить.
Шаг 6: Рендеринг настоящих сообщений
Вернемся в файл index.js и превратим 4 полученных идентификатора в переменные в начале файла.
Вот так выглядят мои, но лучше сделайте это самим:
const instanceLocator = "v1:us1:dfaf1e22-2d33-45c9-b4f8-31f634621d24"
const testToken = "https://us1.pusherplatform.io/services/chatkit_token_provider/v1/dfaf1e22-2d33-45c9-b4f8-31f634621d24/token"
const username = "perborgen"
const roomId = 9796712
Сделав это, мы наконец сможем соединиться с Chatkit. Это произойдет в компоненте App
, а точнее - в методе componentDidMount(). Этот метод нужно использовать при подключении компонентов React JS к API.
Сначала создадим chatManager
:
componentDidMount() {
const chatManager = new Chatkit.ChatManager({
instanceLocator: instanceLocator,
userId: username,
tokenProvider: new Chatkit.TokenProvider({
url: testToken
})
})
...а теперь вызовем chatManager.connect()
, чтобы соединиться с API:
chatManager.connect().then(currentUser => {
currentUser.subscribeToRoom({
roomId: roomId,
hooks: {
onNewMessage: message => {
this.setState({
messages: [...this.state.messages, message]
})
}
}
})
})
}
Теперь у нас есть доступ к объекту currentUser
- это интерфейс, нужный для взаимодействия с API.
Важно: Так как currentUser нам еще понадобится, сохраним его так: this.currentUser = currentUser.
Затем вызовем currentUser.subscribeToRoom()
и передадим туда roomId
и onNewMessage
хук.
Хук onNewMessage
срабатывает каждый раз, когда в чат-комнату передается новое сообщение. Каждый раз мы будем просто добавлять новое сообщение в конце this.state.messages
.
Благодаря этому приложение получит данные из API и отрисует их на странице.
Это прекрасно: теперь у нас есть скелет соединения клиент-сервер.
Шаг 7: Обработка пользовательских команд
Далее будет необходимо создать «контролируемый» компонент SendMessageForm
. Он контролирует, что проходит рендеринг в поле ввода с помощью state
.
Взгляните на метод render() и обратите внимание на выделенные строки:
class SendMessageForm extends React.Component {
render() {
return (
<form
className="send-message-form">
<input
onChange={this.handleChange}
value={this.state.message}
placeholder="Type your message and hit ENTER"
type="text" />
</form>
)
}
}
Здесь происходит 2 вещи:
- Слушатель событий onChange следит за пользовательским вводом, поэтому может сработать метод handleChange;
- Устанавливается значение value поля ввода при помощи this.state.message.
Связь между этими действиями можно найти в методе handleChange(). Он просто обновляет состояние, когда пользователь что-то вносит в поле ввода:
handleChange(e) {
this.setState({
message: e.target.value
})
}
Из-за этого происходит повторный рендеринг страницы. Так как поле ввода задано явно при помощи value={this.state.message}
, оно тоже обновляется.
Так что, хоть пользователю и кажется, что приложение срабатывает в тот же миг, когда он что-то набирает, на самом деле информация сначала проходит через state
, и только затем React обновляет интерфейс.
Чтобы закончить этот шаг, дадим компоненту constructor
. Здесь произведем инициализацию state
и свяжем this
и метод handleChange():
constructor() {
super()
this.state = {
message: ''
}
this.handleChange = this.handleChange.bind(this)
}
Привязка к методу handleChange() нужна, чтобы внутри него у нас был доступ к this
. Так работает JavaScript: this
по умолчанию является неопределенным в теле функции.
Шаг 8: Отправка сообщений
Наш компонент SendMessageForm
практически завершен, но нужно разобраться с отправкой информации. Нужно будет получать и отправлять сообщения!
Для этого привяжем обработчик событий handleSubmit() к прослушивателю onSubmit
в <form>
.
render() {
return (
<form
onSubmit={this.handleSubmit}
className="send-message-form">
<input
onChange={this.handleChange}
value={this.state.message}
placeholder="Type your message and hit ENTER"
type="text" />
</form>
)
}
Так как содержимое поля ввода содержится в this.state.message
, передать данные будет легко. Мы просто сделаем так:
handleSubmit(e) {
e.preventDefault()
this.props.sendMessage(this.state.message)
this.setState({
message: ''
})
}
Здесь мы вызываем sendMessage
и передаем this.state.message
как параметр. Вас это может смутить, потому что мы еще не создали метод sendMessage
. Однако мы сделаем это в следующем шаге, так как этот метод живет внутри компонента App
. Не волнуйтесь!
Далее мы очищаем поле ввода, присваивая this.state.message
пустую строку.
Вот компонент SendMessageForm
целиком. Заметьте, что мы также связали this
с методом handleSubmit():
class SendMessageForm extends React.Component {
constructor() {
super()
this.state = {
message: ''
}
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange(e) {
this.setState({
message: e.target.value
})
}
handleSubmit(e) {
e.preventDefault()
this.props.sendMessage(this.state.message)
this.setState({
message: ''
})
}
render() {
return (
<form
onSubmit={this.handleSubmit}
className="send-message-form">
<input
onChange={this.handleChange}
value={this.state.message}
placeholder="Type your message and hit ENTER"
type="text" />
</form>
)
}
}
Шаг 9: Отправка сообщений в Chatkit
Теперь мы готовы отправлять сообщения в Chatkit. Это делается в компоненте App
, где мы создадим метод под названием this.sendMessage
:
sendMessage(text) {
this.currentUser.sendMessage({
text,
roomId: roomId
})
}
Нам нужен всего один параметр (текст), который просто вызывает this.currentUser.sendMessage()
. Напоследок передаем его компоненту <SendMessageForm>
как свойство:
/* App component */
render() {
return (
<div className="app">
<Title />
<MessageList messages={this.state.messages} />
<SendMessageForm sendMessage={this.sendMessage} />
)
}
Так, мы передали обработчик, чтобы SendMessageForm
могло заставлять его начинать работу, когда происходит ввод данных.
Шаг 10: Создание компонента Title
Завершим программу созданием компонента Title. Это обычный функциональный компонент, то есть функция, возвращающая выражение JSX.
function Title() {
return <p class="title">My awesome chat app</p>
}
Хорошо время от времени использовать функциональные компоненты, так как они содержат больше ограничений, кроме классовых компонентов, из-за чего в них реже случаются баги.
Результат
Все, теперь вы создали собственное React приложение, которое можно использовать для общения с друзьями!
Похлопайте себя по спине, если кодили вместе со мной до самого конца.