How to create a chat app using React?

Aryan Arabshahi
July 23, 2021
Share:

The first step to create a chat application is to create a socket server which we talked about in detail in the previous post “How to create a WebSocket in Python”. In this tutorial, we're going to connect to the socket server using SocketIO to send and receive messages. First of all, get the simple chat app from the repository:

git clone https://github.com/aryan-arabshahi/code-with-coffee-samples.git
cd ./code-with-coffee-samples/simple_chat/simple_chat/react_app

If you want to run the react project, you can use:

yarn
yarn start

Or you can install and run the python package which has the pre-build react project.

Let's have a look into the project structure:

react_app
├── package.json
├── README.md
├── src
│   ├── App.js
│   ├── App.test.js
│   ├── components
│   │   ├── chat.jsx
│   │   └── side-bar.jsx
│   ├── config.js
│   ├── index.css
│   ├── index.js
│   ├── logo.svg
│   ├── reportWebVitals.js
│   ├── setupTests.js
│   └── socketio.jsx
└── yarn.lock

The “config.js” file has the necessary configs that you can customize.

 

The “App.js” is the entry point of the project and the “chat.js” is the main component that handles the chat events. In order to add the SocketIO connection to the project, we created the “socketio.js”:

import { createContext } from 'react';
import socketio from 'socket.io-client';
import config from './config';

export const SocketIO = socketio.connect(config.socketServer);

export const SocketContext = createContext();

 

And the socket context has been used in “app.js”:

import './assets/css/style.css';
import Chat from './components/chat';
import SideBar from './components/side-bar';
import { SocketIO, SocketContext } from './socketio'

function App() {
    return (
        <SocketContext.Provider value={SocketIO}>
            <SideBar/>
            <Chat/>
        </SocketContext.Provider>
    );
}

export default App;

In this way, we have access to the socketio object in the child components.

Let's take a look into the “chat.js”. We created an event handler to manage the received messages and set them with a certain schema in the receivedMessage state. Also, There is a useEffect block to detect the changes of it:

const socketio = useContext(SocketContext);

const onMessageReceived = (data) => {

    setReceivedMessage(
        MessageData({
            sender: Sender[data.sender],
            message: data.message,
        })
    );

}

useEffect(() => {

    if (receivedMessage !== null) {
        setMessagesList(messagesList.concat(receivedMessage));
    }

}, [receivedMessage]);

useEffect(() => {
    socketio.on('receive_message', onMessageReceived);
    return () => {
        socketio.off('receive_message', onMessageReceived);
    };
}, [socketio]);

There is another state named “messagesList” which holds all the sent and the received messages that finally will be shown in the chat area. To send a message, there is an onSubmit event handler that read the message value and adds it to the "messagesList" and finally the new message will be sent using the emmit method of the socketio:

const onSubmit = (e) => {
    e.preventDefault();

    if (message !== null) {
        sendMessage(message);
    }

}

const sendMessage = (message) => {

    setMessagesList(messagesList.concat([
        MessageData({
            sender: Sender.me,
            message: message,
        })
    ]));

}

useEffect(() => {

    /*
    * Get the last inserted message and send it if is from me
    */
    const messagesCount = messagesList.length;
    if (messagesCount && messagesList[messagesCount -1].sender === Sender.me) {
        socketio.emit('send_message', message);
        setMessage(null);
    }

    scrollToBottom();

}, [messagesList]);

Now, we are sending and receiving the messages using SocketIO :)