Чаты окружают нас повсюду, от Whatsapp до Facebook и Instagram, почти каждая платформа предлагает чат в той или иной вариации.
В современном цифровом мире мы все стали мобильными! Незадолго до этой статьи я написал другу сообщение в Whatsapp.

Чаты — это весело, вы отправляете сообщение человеку или группе, они видят сообщение и отвечают вам. Простой, но сложный.
Чтобы разработать приложение для чата, вам нужно узнавать о новых сообщениях сразу после их поступления.
В этой статье мы сделаем нечто, немного отличающееся от предыдущего руководства по React. Мы создадим экран входа, где вы сможете ввести свое имя, создать группы, к которым люди могут присоединиться, и показывать сообщения в реальном времени между людьми в группе.
Получение оперативной информации с сервера ℹ️
Есть два способа получить оперативную информацию с вашего сервера о новой ставке:
Используйте HTTP-запрос с длительным опросом, в основном HTTP-запрос каждые 5–10 секунд для получения информации о новой ставке.
Используйте открытый сокет (веб-сокеты), чтобы получать информацию непосредственно с сервера при поступлении новой заявки.
В этой статье я расскажу о веб-сокетах и, в частности, о библиотеке Node.js — Socket.io.
Socket.io — это популярная библиотека JavaScript, которая позволяет нам создавать двустороннюю связь в режиме реального времени между программными приложениями и сервером Node.js.
Novu — первая инфраструктура уведомлений с открытым исходным кодом
Просто краткая справка о нас. Novu — первая инфраструктура уведомлений с открытым исходным кодом. Мы в основном помогаем управлять всеми уведомлениями о продуктах. Это может быть In-App (значок колокольчика, как у вас в сообществе разработчиков — веб-сокеты), электронные письма, SMS и так далее.
Я был бы очень рад, если бы вы могли дать нам звезду! Это поможет мне делать больше статей каждую неделю 🚀
https://github.com/novuhq/novu

Мы отправляем классные подарки во время Хактоберфеста 😇
Как создать соединение в реальном времени между React Native и Socket.io
В этом руководстве мы создадим приложение для чата с помощью Expo — фреймворка с открытым исходным кодом, который позволяет нам создавать нативные приложения для IOS и Android путем написания кода React и JavaScript.
Установка Экспо
Expo избавляет нас от сложных конфигураций, необходимых для создания собственного приложения с помощью React Native CLI, что делает его самым простым и быстрым способом создания и публикации приложений React Native.
Убедитесь, что на вашем компьютере установлены Expo CLI, Node.js и Git. Затем создайте папку проекта и приложение Expo React Native, запустив приведенный ниже код.
mkdir chat-app
cd chat-app
expo init app
Expo позволяет нам создавать нативные приложения, используя управляемый или голый рабочий процесс. В этом руководстве мы будем использовать пустой управляемый рабочий процесс, поскольку все необходимые настройки уже выполнены.
? Choose a template: › - Use arrow-keys. Return to submit.
----- Managed workflow -----
❯ blank a minimal app as clean as an empty canvas
blank (TypeScript) same as blank but with TypeScript configuration
tabs (TypeScript) several example screens and tabs using react-navigation and TypeScript
----- Bare workflow -----
minimal bare and minimal, just the essentials to get you started
Установите клиентский API Socket.io в приложение React Native.
cd app
expo install socket.io-client
Создайте socket.js в папке utils и скопируйте приведенный ниже код в файл.
mkdir utils
touch socket.js
//👇🏻 Paste within socket.js file
И добавить
import { io } from "socket.io-client";
const socket = io.connect("http://localhost:4000");
export default socket;
Приведенный выше фрагмент кода создает подключение в реальном времени к серверу, размещенному по этому URL-адресу. (Мы создадим сервер в следующем разделе).
Создайте файл styles.js в папке utils и скопируйте приведенный ниже код в файл. Он содержит все стили для приложения чата.
import { StyleSheet } from "react-native";export const styles = StyleSheet.create({ loginscreen: { flex: 1, backgroundColor: "#EEF1FF", alignItems: "center", justifyContent: "center", padding: 12, width: "100%", }, loginheading: { fontSize: 26, marginBottom: 10, }, logininputContainer: { width: "100%", alignItems: "center", justifyContent: "center", }, logininput: { borderWidth: 1, width: "90%", padding: 8, borderRadius: 2, }, loginbutton: { backgroundColor: "green", padding: 12, marginVertical: 10, width: "60%", borderRadius: "50%", elevation: 1, }, loginbuttonText: { textAlign: "center", color: "#fff", fontWeight: "600", }, chatscreen: { backgroundColor: "#F7F7F7", flex: 1, padding: 10, position: "relative", }, chatheading: { fontSize: 24, fontWeight: "bold", color: "green", }, chattopContainer: { backgroundColor: "#F7F7F7", height: 70, width: "100%", padding: 20, justifyContent: "center", marginBottom: 15, elevation: 2, }, chatheader: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", }, chatlistContainer: { paddingHorizontal: 10, }, chatemptyContainer: { width: "100%", height: "80%", alignItems: "center", justifyContent: "center", }, chatemptyText: { fontWeight: "bold", fontSize: 24, paddingBottom: 30 }, messagingscreen: { flex: 1, }, messaginginputContainer: { width: "100%", minHeight: 100, backgroundColor: "white", paddingVertical: 30, paddingHorizontal: 15, justifyContent: "center", flexDirection: "row", }, messaginginput: { borderWidth: 1, padding: 15, flex: 1, marginRight: 10, borderRadius: 20, }, messagingbuttonContainer: { width: "30%", backgroundColor: "green", borderRadius: 3, alignItems: "center", justifyContent: "center", borderRadius: 50, }, modalbutton: { width: "40%", height: 45, backgroundColor: "green", borderRadius: 5, alignItems: "center", justifyContent: "center", color: "#fff", }, modalbuttonContainer: { flexDirection: "row", justifyContent: "space-between", marginTop: 10, }, modaltext: { color: "#fff", }, modalContainer: { width: "100%", borderTopColor: "#ddd", borderTopWidth: 1, elevation: 1, height: 400, backgroundColor: "#fff", position: "absolute", bottom: 0, zIndex: 10, paddingVertical: 50, paddingHorizontal: 20, }, modalinput: { borderWidth: 2, padding: 15, }, modalsubheading: { fontSize: 20, fontWeight: "bold", marginBottom: 15, textAlign: "center", }, mmessageWrapper: { width: "100%", alignItems: "flex-start", marginBottom: 15, }, mmessage: { maxWidth: "50%", backgroundColor: "#f5ccc2", padding: 15, borderRadius: 10, marginBottom: 2, }, mvatar: { marginRight: 5, }, cchat: { width: "100%", flexDirection: "row", alignItems: "center", borderRadius: 5, paddingHorizontal: 15, backgroundColor: "#fff", height: 80, marginBottom: 10, }, cavatar: { marginRight: 15, }, cusername: { fontSize: 18, marginBottom: 5, fontWeight: "bold", }, cmessage: { fontSize: 14, opacity: 0.7, }, crightContainer: { flexDirection: "row", justifyContent: "space-between", flex: 1, }, ctime: { opacity: 0.5, }, });
Установите React Navigation и его зависимости. React Navigation позволяет нам переходить с одного экрана на другой в приложении React Native.
npm install @react-navigation/native
npx expo install react-native-screens react-native-safe-area-context
Настройка сервера Socket.io Node.js
Здесь я проведу вас через создание сервера Socket.io Node.js для связи в реальном времени с приложением React Native.
Создайте папку server в папке проекта.
cd chat-app
mkdir server
Перейдите в папку сервера и создайте файл package.json.
cd server & npm init -y
Установите Express.js, CORS, Nodemon и Socket.io Server API.
npm install express cors nodemon socket.io
Express.js — это быстрый минималистичный фреймворк, предоставляющий несколько функций для создания веб-приложений на Node.js. CORS — это пакет Node.js, который обеспечивает связь между разными доменами.
Nodemon — это инструмент Node.js, который автоматически перезапускает сервер после обнаружения изменений в файле, а Socket.io позволяет нам настроить соединение в реальном времени на сервере.
Создайте файл index.js — точку входа на сервер Node.js.
touch index.js
Настройте простой сервер Node.js с помощью Express.js. Приведенный ниже фрагмент кода возвращает объект JSON при посещении http://localhost:4000/api в браузере.
//👇🏻 index.js const express = require("express"); const app = express(); const PORT = 4000;app.use(express.urlencoded({ extended: true })); app.use(express.json());app.get("/api", (req, res) => { res.json({ message: "Hello world", }); });app.listen(PORT, () => { console.log(`Server listening on ${PORT}`); });
Импортируйте библиотеки HTTP и CORS, чтобы разрешить передачу данных между клиентским и серверным доменами.
const express = require("express"); const app = express(); const PORT = 4000;app.use(express.urlencoded({ extended: true })); app.use(express.json());//👇🏻 New imports const http = require("http").Server(app); const cors = require("cors");app.use(cors());app.get("/api", (req, res) => { res.json({ message: "Hello world", }); });http.listen(PORT, () => { console.log(`Server listening on ${PORT}`); });
Затем добавьте Socket.io в проект, чтобы создать соединение в реальном времени. Перед блоком app.get() скопируйте приведенный ниже код:
//👇🏻 New imports ..... const socketIO = require('socket.io')(http, { cors: { origin: "<http://localhost:3000>" } });//👇🏻 Add this before the app.get() block socketIO.on('connection', (socket) => { console.log(`⚡: ${socket.id} user just connected!`);socket.on('disconnect', () => { socket.disconnect() console.log('🔥: A user disconnected'); }); });
Из приведенного выше фрагмента кода функция socket.io("connection") устанавливает соединение с приложением React, затем создает уникальный идентификатор для каждого сокета и записывает идентификатор в консоль всякий раз, когда вы обновляете приложение.
Когда вы обновляете или закрываете приложение, сокет запускает событие разъединения, показывающее, что пользователь отключился от сокета.
Настройте Nodemon, добавив команду запуска в список скриптов в файле package.json. Фрагмент кода ниже запускает сервер с помощью Nodemon.
//👇🏻 In server/package.json"scripts": { "test": "echo \\"Error: no test specified\\" && exit 1", "start": "nodemon index.js" },
Теперь вы можете запустить сервер с помощью Nodemon, используя приведенную ниже команду.
npm start
Создание пользовательского интерфейса
Здесь мы создадим пользовательский интерфейс для приложения чата, чтобы пользователи могли входить в систему, создавать комнаты чата и отправлять сообщения. Приложение разделено на три экрана — экран входа в систему, экран чата и экран обмена сообщениями.

Во-первых, давайте настроим React Navigation.
Создайте папку screens в папке приложения, добавьте компоненты входа, чата и обмена сообщениями и визуализируйте в них текст "Hello World".
mkdir screens
touch Login.js Chat.js Messaging.js
Скопируйте приведенный ниже код в файл App.js в папке приложения.
import React from "react";//👇🏻 app screens import Login from "./screens/Login"; import Messaging from "./screens/Messaging"; import Chat from "./screens/Chat";//👇🏻 React Navigation configurations import { NavigationContainer } from "@react-navigation/native"; import { createNativeStackNavigator } from "@react-navigation/native-stack";const Stack = createNativeStackNavigator();export default function App() { return ( <NavigationContainer> <Stack.Navigator> <Stack.Screen name='Login' component={Login} options={{ headerShown: false }} /><Stack.Screen name='Chat' component={Chat} options={{ title: "Chats", headerShown: false, }} /> <Stack.Screen name='Messaging' component={Messaging} /> </Stack.Navigator> </NavigationContainer> ); }
Экран входа
Скопируйте приведенный ниже код в файл Login.js.
import React, { useState } from "react"; import { Text, SafeAreaView, View, TextInput, Pressable, Alert, } from "react-native";//👇🏻 Import the app styles import { styles } from "../utils/styles";const Login = ({ navigation }) => { const [username, setUsername] = useState("");//👇🏻 checks if the input field is empty const handleSignIn = () => { if (username.trim()) { //👇🏻 Logs the username to the console console.log({ username }); } else { Alert.alert("Username is required."); } };return ( <SafeAreaView style={styles.loginscreen}> <View style={styles.loginscreen}> <Text style={styles.loginheading}>Sign in</Text> <View style={styles.logininputContainer}> <TextInput autoCorrect={false} placeholder='Enter your username' style={styles.logininput} onChangeText={(value) => setUsername(value)} /> </View><Pressable onPress={handleSignIn} style={styles.loginbutton}> <View> <Text style={styles.loginbuttonText}>Get Started</Text> </View> </Pressable> </View> </SafeAreaView> ); };export default Login;
Фрагмент кода принимает имя пользователя от пользователя и регистрирует его в консоли.
Давайте обновим код и сохраним имя пользователя с помощью Async Storage, чтобы пользователям не нужно было входить в приложение каждый раз, когда они запускают приложение.
💡 *Async Storage — это пакет React Native, используемый для хранения строковых данных в нативных приложениях. Оно похоже на локальное хранилище в Интернете и может использоваться для хранения токенов и различных данных в строковом формате.*
Запустите приведенный ниже код, чтобы установить Async Storage.
expo install @react-native-async-storage/async-storage
Обновите функцию handleSignIn, чтобы сохранить имя пользователя через AsyncStorage.
import AsyncStorage from "@react-native-async-storage/async-storage";const storeUsername = async () => { try { //👇🏻 async function - saves the username to AsyncStorage // redirecting to the Chat page await AsyncStorage.setItem("username", username); navigation.navigate("Chat"); } catch (e) { Alert.alert("Error! While saving username"); } };const handleSignIn = () => { if (username.trim()) { //👇🏻 calls AsyncStorage function storeUsername(); } else { Alert.alert("Username is required."); } };
Чат
Здесь мы обновим пользовательский интерфейс для экрана Chat, чтобы отображать доступные комнаты чата, позволять пользователям создавать их и переходить к экрану Messaging при выборе каждой комнаты.

Скопируйте приведенный ниже код в файл Chat.js.
import React from "react"; import { View, Text, Pressable, SafeAreaView, FlatList } from "react-native"; import { Feather } from "@expo/vector-icons";import ChatComponent from "../component/ChatComponent"; import { styles } from "../utils/styles";const Chat = () => {//👇🏻 Dummy list of rooms const rooms = [ { id: "1", name: "Novu Hangouts", messages: [ { id: "1a", text: "Hello guys, welcome!", time: "07:50", user: "Tomer", }, { id: "1b", text: "Hi Tomer, thank you! 😇", time: "08:50", user: "David", }, ], }, { id: "2", name: "Hacksquad Team 1", messages: [ { id: "2a", text: "Guys, who's awake? 🙏🏽", time: "12:50", user: "Team Leader", }, { id: "2b", text: "What's up? 🧑🏻💻", time: "03:50", user: "Victoria", }, ], }, ];return ( <SafeAreaView style={styles.chatscreen}> <View style={styles.chattopContainer}> <View style={styles.chatheader}> <Text style={styles.chatheading}>Chats</Text>{/* 👇🏻 Logs "ButtonPressed" to the console when the icon is clicked */} <Pressable onPress={() => console.log("Button Pressed!")}> <Feather name='edit' size={24} color='green' /> </Pressable> </View> </View><View style={styles.chatlistContainer}> {rooms.length > 0 ? ( <FlatList data={rooms} renderItem={({ item }) => <ChatComponent item={item} />} keyExtractor={(item) => item.id} /> ) : ( <View style={styles.chatemptyContainer}> <Text style={styles.chatemptyText}>No rooms created!</Text> <Text>Click the icon above to create a Chat room</Text> </View> )} </View> </SafeAreaView> ); };export default Chat;
- Из фрагмента кода выше:
- Я создал фиктивный список комнат, затем отрендерил их через FlatList в
ChatComponent. (еще не создано) - Поскольку комнаты могут быть либо пустыми, либо заполненными, условный оператор определяет отображаемый компонент.

Затем создайте ChatComponent в папке компонента. Он представляет собой предварительный просмотр имени каждого чата, времени, последнего отправленного сообщения и перенаправляет пользователей на компонент Messaging при нажатии.
Скопируйте приведенный ниже код в файл components/ChatComponent.js.
import { View, Text, Pressable } from "react-native"; import React, { useLayoutEffect, useState } from "react"; import { Ionicons } from "@expo/vector-icons"; import { useNavigation } from "@react-navigation/native"; import { styles } from "../utils/styles";const ChatComponent = ({ item }) => { const navigation = useNavigation(); const [messages, setMessages] = useState({});//👇🏻 Retrieves the last message in the array from the item prop useLayoutEffect(() => { setMessages(item.messages[item.messages.length - 1]); }, []);///👇🏻 Navigates to the Messaging screen const handleNavigation = () => { navigation.navigate("Messaging", { id: item.id, name: item.name, }); };return ( <Pressable style={styles.cchat} onPress={handleNavigation}> <Ionicons name='person-circle-outline' size={45} color='black' style={styles.cavatar} /><View style={styles.crightContainer}> <View> <Text style={styles.cusername}>{item.name}</Text><Text style={styles.cmessage}> {messages?.text ? messages.text : "Tap to start chatting"} </Text> </View> <View> <Text style={styles.ctime}> {messages?.time ? messages.time : "now"} </Text> </View> </View> </Pressable> ); };export default ChatComponent;
Поздравляю💃🏻! Теперь мы можем отобразить список комнат и перенаправить пользователя на экран Messaging.
Прежде чем мы продолжим, давайте создадим пользовательский модальный компонент, который позволяет пользователям создавать новую группу (комнату), когда мы нажимаем значок заголовка.

Создайте файл Modal.js в папке компонентов, импортируйте его на экран чата и переключайте его всякий раз, когда мы нажимаем значок заголовка.
import React from "react"; import { View, Text, Pressable, SafeAreaView, FlatList } from "react-native"; import { Feather } from "@expo/vector-icons"; import ChatComponent from "../component/ChatComponent"; import { styles } from "../utils/styles";//👇🏻 The Modal component import Modal from "../component/Modal";const Chat = () => { const [visible, setVisible] = useState(false);//...other variables return ( <SafeAreaView style={styles.chatscreen}> <View style={styles.chattopContainer}> <View style={styles.chatheader}> <Text style={styles.chatheading}>Chats</Text>{/* Displays the Modal component when clicked */} <Pressable onPress={() => setVisible(true)}> <Feather name='edit' size={24} color='green' /> </Pressable> </View> </View><View style={styles.chatlistContainer}>...</View> {/* Pass setVisible as prop in order to toggle the display within the Modal component. */} {visible ? <Modal setVisible={setVisible} /> : ""} </SafeAreaView> ); };export default Chat;
Скопируйте приведенный ниже код в файл Modal.js.
import { View, Text, TextInput, Pressable } from "react-native"; import React, { useState } from "react"; import { styles } from "../utils/styles";const Modal = ({ setVisible }) => { const [groupName, setGroupName] = useState("");//👇🏻 Function that closes the Modal component const closeModal = () => setVisible(false);//👇🏻 Logs the group name to the console const handleCreateRoom = () => { console.log({ groupName }); closeModal(); }; return ( <View style={styles.modalContainer}> <Text style={styles.modalsubheading}>Enter your Group name</Text> <TextInput style={styles.modalinput} placeholder='Group name' onChangeText={(value) => setGroupName(value)} /><View style={styles.modalbuttonContainer}> <Pressable style={styles.modalbutton} onPress={handleCreateRoom}> <Text style={styles.modaltext}>CREATE</Text> </Pressable> <Pressable style={[styles.modalbutton, { backgroundColor: "#E14D2A" }]} onPress={closeModal} > <Text style={styles.modaltext}>CANCEL</Text> </Pressable> </View> </View> ); };export default Modal;
Экран сообщений
Скопируйте приведенный ниже код в файл Messaging.js.
import React, { useLayoutEffect, useState } from "react"; import { View, TextInput, Text, FlatList, Pressable } from "react-native"; import AsyncStorage from "@react-native-async-storage/async-storage"; import MessageComponent from "../component/MessageComponent"; import { styles } from "../utils/styles";const Messaging = ({ route, navigation }) => { const [chatMessages, setChatMessages] = useState([ { id: "1", text: "Hello guys, welcome!", time: "07:50", user: "Tomer", }, { id: "2", text: "Hi Tomer, thank you! 😇", time: "08:50", user: "David", }, ]); const [message, setMessage] = useState(""); const [user, setUser] = useState("");//👇🏻 Access the chatroom's name and id const { name, id } = route.params;//👇🏻 This function gets the username saved on AsyncStorage const getUsername = async () => { try { const value = await AsyncStorage.getItem("username"); if (value !== null) { setUser(value); } } catch (e) { console.error("Error while loading username!"); } };//👇🏻 Sets the header title to the name chatroom's name useLayoutEffect(() => { navigation.setOptions({ title: name }); getUsername() }, []);/*👇🏻 This function gets the time the user sends a message, then logs the username, message, and the timestamp to the console. */ const handleNewMessage = () => { const hour = new Date().getHours() < 10 ? `0${new Date().getHours()}` : `${new Date().getHours()}`;const mins = new Date().getMinutes() < 10 ? `0${new Date().getMinutes()}` : `${new Date().getMinutes()}`;console.log({ message, user, timestamp: { hour, mins }, }); };return ( <View style={styles.messagingscreen}> <View style={[ styles.messagingscreen, { paddingVertical: 15, paddingHorizontal: 10 }, ]} > {chatMessages[0] ? ( <FlatList data={chatMessages} renderItem={({ item }) => ( <MessageComponent item={item} user={user} /> )} keyExtractor={(item) => item.id} /> ) : ( "" )} </View><View style={styles.messaginginputContainer}> <TextInput style={styles.messaginginput} onChangeText={(value) => setMessage(value)} /> <Pressable style={styles.messagingbuttonContainer} onPress={handleNewMessage} > <View> <Text style={{ color: "#f2f0f1", fontSize: 20 }}>SEND</Text> </View> </Pressable> </View> </View> ); };export default Messaging;
Приведенный выше фрагмент кода отображает сообщения в каждом чате с помощью компонента MessageComponent.
Создайте файл MessageComponent и скопируйте в него приведенный ниже код:
import { View, Text } from "react-native"; import React from "react"; import { Ionicons } from "@expo/vector-icons"; import { styles } from "../utils/styles";export default function MessageComponent({ item, user }) { const status = item.user !== user;return ( <View> <View style={ status ? styles.mmessageWrapper : [styles.mmessageWrapper, { alignItems: "flex-end" }] } > <View style={{ flexDirection: "row", alignItems: "center" }}> <Ionicons name='person-circle-outline' size={30} color='black' style={styles.mavatar} /> <View style={ status ? styles.mmessage : [styles.mmessage, { backgroundColor: "rgb(194, 243, 194)" }] } > <Text>{item.text}</Text> </View> </View> <Text style={{ marginLeft: 40 }}>{item.time}</Text> </View> </View> ); }
Из приведенного выше фрагмента кода переменная status проверяет, совпадает ли пользовательский ключ в сообщении с текущим пользователем, чтобы определить, как выравнивать сообщения.

Мы завершили пользовательский интерфейс для приложения!🎊 Теперь давайте узнаем, как общаться с сервером Socket.io, создавать чаты и отправлять сообщения в режиме реального времени через Socket.io.
Создание чатов с помощью Socket.io в React Native
В этом разделе я проведу вас через создание чатов на сервере Socket.io и их отображение в приложении.
Обновите файл Modal.js, чтобы отправить сообщение на сервер при создании нового чата.
import { View, Text, TextInput, Pressable } from "react-native"; import React, { useState } from "react"; import { styles } from "../utils/styles";//👇🏻 Import socket from the socket.js file in utils folder import socket from "../utils/socket";const Modal = ({ setVisible }) => { const closeModal = () => setVisible(false); const [groupName, setGroupName] = useState("");const handleCreateRoom = () => { //👇🏻 sends a message containing the group name to the server socket.emit("createRoom", groupName); closeModal(); }; return ( <View style={styles.modalContainer}> <Text style={styles.modalsubheading}>Enter your Group name</Text> <TextInput style={styles.modalinput} placeholder='Group name' onChangeText={(value) => setGroupName(value)} /> <View style={styles.modalbuttonContainer}> {/* 👇🏻 The create button triggers the function*/} <Pressable style={styles.modalbutton} onPress={handleCreateRoom}> <Text style={styles.modaltext}>CREATE</Text> </Pressable><Pressable style={[styles.modalbutton, { backgroundColor: "#E14D2A" }]} onPress={closeModal} > <Text style={styles.modaltext}>CANCEL</Text> </Pressable> </View> </View> ); };export default Modal;
Создайте прослушиватель на внутреннем сервере, который сохраняет имя группы в массив и возвращает весь список.
//👇🏻 Generates random string as the ID const generateID = () => Math.random().toString(36).substring(2, 10);let chatRooms = [ //👇🏻 Here is the data structure of each chatroom // { // id: generateID(), // name: "Novu Hangouts", // messages: [ // { // id: generateID(), // text: "Hello guys, welcome!", // time: "07:50", // user: "Tomer", // }, // { // id: generateID(), // text: "Hi Tomer, thank you! 😇", // time: "08:50", // user: "David", // }, // ], // }, ];socketIO.on("connection", (socket) => { console.log(`⚡: ${socket.id} user just connected!`);socket.on("createRoom", (roomName) => { socket.join(roomName); //👇🏻 Adds the new group name to the chat rooms array chatRooms.unshift({ id: generateID(), roomName, messages: [] }); //👇🏻 Returns the updated chat rooms via another event socket.emit("roomsList", chatRooms); });socket.on("disconnect", () => { socket.disconnect(); console.log("🔥: A user disconnected"); }); });
Кроме того, верните список комнат чата через маршрут API, как показано ниже:
app.get("/api", (req, res) => {
res.json(chatRooms);
});
Обновите файл Chat.js, чтобы получить и прослушать roomsList с сервера и отобразить чаты.
const [rooms, setRooms] = useState([]);//👇🏻 Runs when the component mounts useLayoutEffect(() => { function fetchGroups() { fetch("http://localhost:4000/api") .then((res) => res.json()) .then((data) => setRooms(data)) .catch((err) => console.error(err)); } fetchGroups(); }, []);//👇🏻 Runs whenever there is new trigger from the backend useEffect(() => { socket.on("roomsList", (rooms) => { setRooms(rooms); }); }, [socket]);
Отправка сообщений через Socket.io в React Native
В предыдущем разделе мы могли создавать новые чаты, сохранять их в виде массива на сервере и отображать в приложении. Здесь мы будем обновлять сообщения чата, добавляя новые сообщения в подмассив.
Как отображать сообщения чата
Напомним, что идентификатор каждой комнаты чата передается в компонент обмена сообщениями. Теперь давайте отправим идентификатор на сервер через Socket.io при загрузке экрана.
import React, { useEffect, useLayoutEffect, useState } from "react"; import { View, TextInput, Text, FlatList, Pressable } from "react-native"; import socket from "../utils/socket"; import MessageComponent from "../component/MessageComponent"; import { styles } from "../utils/styles";const Messaging = ({ route, navigation }) => { //👇🏻 The id passed const { name, id } = route.params;//...other functionsuseLayoutEffect(() => { navigation.setOptions({ title: name });//👇🏻 Sends the id to the server to fetch all its messages socket.emit("findRoom", id); }, []);return <View style={styles.messagingscreen}>...</View>; };export default Messaging;
Создайте прослушиватель событий на сервере.
socket.on("findRoom", (id) => {
//👇🏻 Filters the array by the ID
let result = chatRooms.filter((room) => room.id == id);
//👇🏻 Sends the messages to the app
socket.emit("foundRoom", result[0].messages);
});
Затем прослушайте событие foundRoom и отобразите сообщения пользователю.
//👇🏻 This runs only initial mount useLayoutEffect(() => { navigation.setOptions({ title: name }); socket.emit("findRoom", id); socket.on("foundRoom", (roomChats) => setChatMessages(roomChats)); }, []);//👇🏻 This runs when the messages are updated. useEffect(() => { socket.on("foundRoom", (roomChats) => setChatMessages(roomChats)); }, [socket])
Как создавать новые сообщения
Чтобы создавать новые сообщения, нам нужно обновить функцию handleNewMessage, чтобы отправить свойство сообщения на сервер и добавить его в массив messages.
const handleNewMessage = () => { const hour = new Date().getHours() < 10 ? `0${new Date().getHours()}` : `${new Date().getHours()}`;const mins = new Date().getMinutes() < 10 ? `0${new Date().getMinutes()}` : `${new Date().getMinutes()}`;socket.emit("newMessage", { message, room_id: id, user, timestamp: { hour, mins }, }); };
Прослушайте событие на сервере и обновите массив chatRoom.
socket.on("newMessage", (data) => { //👇🏻 Destructures the property from the object const { room_id, message, user, timestamp } = data;//👇🏻 Finds the room where the message was sent let result = chatRooms.filter((room) => room.id == room_id);//👇🏻 Create the data structure for the message const newMessage = { id: generateID(), text: message, user, time: `${timestamp.hour}:${timestamp.mins}`, }; //👇🏻 Updates the chatroom messages socket.to(result[0].name).emit("roomMessage", newMessage); result[0].messages.push(newMessage);//👇🏻 Trigger the events to reflect the new changes socket.emit("roomsList", chatRooms); socket.emit("foundRoom", result[0].messages); });
Заключение
Итак, вы узнали, как настроить Socket.io в приложении React Native и Node.js, сохранить данные с помощью Async Storage и обмениваться данными между сервером и приложением Expo через Socket.io.
Socket.io — отличный инструмент с отличными функциями, который позволяет нам создавать эффективные приложения в режиме реального времени, такие как веб-сайты для ставок на спорт, приложения для аукционов и торговли на рынке Форекс и, конечно же, приложения для чата, создавая прочные соединения с Node.js. сервер.
Не стесняйтесь улучшать приложение:
- добавление аутентификации
- сохранение токена с помощью Async Storage
- добавление базы данных в реальном времени для сообщений, и
- добавление push-уведомлений с пакетом выставочное уведомление.
Исходный код этого руководства доступен здесь:
https://github.com/novuhq/blog/tree/main/chat-app-reactnative-socketIO
Спасибо за прочтение!💃🏻
P.S. Novu присылает потрясающие подарки на Hacktoberfest! Приходите и участвуйте! Будем рады, если вы поддержите нас, поставив звезду! ⭐️
https://github.com/novuhq/novu
Создавайте приложения с повторно используемыми компонентами, такими как Lego.

Инструмент с открытым исходным кодом Bit помогает более чем 250 000 разработчиков создавать приложения с компонентами.
Превратите любой пользовательский интерфейс, функцию или страницу в компонент многократного использования — и поделитесь им со своими приложениями. Легче сотрудничать и строить быстрее.
Разделите приложения на компоненты, чтобы упростить разработку приложений, и наслаждайтесь наилучшими возможностями для рабочих процессов, которые вы хотите: