This tutorial is for you if you are a software developer, engineer or are just interested in programming. This walk-through is open source and free; MIT style. You can check out the full React Chat GitHub repository.
React is a JavaScript library that empowers you to make sophisticated front-end applications that can handle business logic in a fast and efficient manner. We’ll use React to build out our web application frontend for our robust chat app. The unique benefit of React, aside from it having one of the largest JavaScript communities and incredible flexibility, is its compatibility with React Native, allowing us to easily turn our web app into a native mobile app for iOS and Android.
In this tutorial, we’ll build a simple, yet featured rich chat application with React and PubNub ChatEngine. React coupled with the material-UI will be used to organize and enhance our application, and ChatEngine is going to be used as the backbone messaging infrastructure and framework to connect our chat users.
Before we get coding, we need to have a deeper understand of what React is and what it provides for us. Primarily, React is built on JavaScript. This means that we can use our existing understanding of JavaScript and still be fairly comfortable with React.
The main thing that differentiates React from the rest, is the idea of components and the lifecycle within components. If you don’t have too much experience with React, don’t fret! I recommend having a look at the official React Docs before we go on but it isn’t required.
Let’s start coding our react chat app! To make it easier, go ahead and pull from the repo: React Chat GitHub Repository.
We need to do a couple things before we get into the code. The first is the Node Package Manager (NPM) which will let us add the packages we need to get all the juicy functionality we need. To get NPM, we need to get the latest version of Node and with that, we’ll have the npm/npx commands available to use in the terminal. Once that’s up and running, we’ll use the terminal to install some prerequisite packages and create the project hierarchy ( it’ll save us some time later down the line).
## Enter these on your command line. ## If you have not already, install Node.js (preferably LTS). npx create-react-app react-chat-engine-app ## Change into the new directory cd react-chat-engine-app npm start
Using the npx command sets up a boilerplate React project with the required packages and the preferred folder structure as described by the React development team. Once we run npm start, we should see a welcome page open up on the url “localhost:3000”
You’ll see that the instance will be running in the terminal. Be sure to keep that window open because it will allow us to see hot updates as we make them.
The best way to use ChatEngine is to install the package using NPM
npm install chat-engine --save
Running that command will get us the prerequisites for getting our app to be able to chat.
Now that we have a rudimentary React project created, we can start adding some flavor to it. All we’re going to do is initialize the ChatEngine Object. We’ll go through the functionality more in-depth in a bit.
react-chat-engine-app/src/index.js
import React, { Component } from 'react'; import ChatEngineCore from 'chat-engine'; const now = new Date().getTime(); const username = ['user', now].join('-'); const ChatClient = ChatEngineCore.create({ publishKey: 'your-pub-key', subscribeKey: 'your-sub-key' }, { globalChannel: 'chatting' }); class App extends Component { constructor(props) { super(props); this.chat = new ChatClient.Chat(`BasicChatApp`); } render(){ <div> </div> } } ChatClient.on('$.ready', () => { ReactDOM.render(<App />, document.getElementById('root')); });
Since ChatEngine relies on the PubNub’s Data Stream Network, we need the PubNub Publish/Subscribe keys to get get-started. configure ChatEngine and get your keys, use the form below:.
In the previous step, we were able to add the primary backend feature which would let our app communicate with other instances. Now, the next step is to connect
For displaying the chat messages, we use the <ion-list> with <ion-grid> UI elements.
The entire HTML code of the app UI is declared in home.html. You can overwrite the file as per the new UI declaration for this app.
react-chat-engine-app/src/index.js (Modified File)
import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import ChatEngineCore from 'chat-engine'; import { withStyles } from '@material-ui/core/styles'; import Card from '@material-ui/core/Card'; import CardActions from '@material-ui/core/CardActions'; import CardContent from '@material-ui/core/CardContent'; import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; import Button from '@material-ui/core/Button'; import Typography from '@material-ui/core/Typography'; import Input from '@material-ui/core/Input'; import opengraph from 'chat-engine-open-graph'; const now = new Date().getTime(); const username = ['user', now].join('-'); const ChatClient = ChatEngineCore.create({ publishKey: 'your-pub-key', subscribeKey: 'your-sub-key' }, { globalChannel: 'chatting' }); ChatClient.connect(username, { signedOnTime: now }, 'auth-key'); const styles = { card: { maxWidth: 345, margin: '0 auto', float: 'none', marginbottom: '10px' }, openCard:{ maxWidth: 200 }, openMedia: { height: 80, }, media: { objectFit: 'cover', }, container: { display: 'flex', flexWrap: 'wrap', }, }; class Message extends Component{ render () { return ( <div > { this.props.uuid }: { this.props.text } </div> ); } }; class App extends Component { constructor(props) { super(props); this.chat = new ChatClient.Chat(`BasicChatApp`); } sendChat = () => { console.log("Sending Chat"); } setChatInput = (event) => { this.setState({ chatInput: event.target.value }) } componentDidMount() { } handleKeyPress = (e) => { if (e.key === 'Enter') { this.sendChat(); } } render(){ const { classes } = this.props; return( <Card className={classes.card}> <CardContent> <Typography gutterBottom variant="headline" component="h2"> Messages </Typography> <div className={classes.root}> <List component="nav"> <ListItem> <Typography component="div"> { this.state.messages } </Typography> </ListItem> </List> </div> </CardContent> <CardActions> <Input placeholder="Enter a message" value={this.state.chatInput} className={classes.input} onKeyDown={this.handleKeyPress} onChange={this.setChatInput} inputProps=aria-label /> <Button size="small" color="primary"> Github </Button> <Button size="small" color="primary"> Exit </Button> </CardActions> </Card> ); } } const ChatComponent = withStyles(styles)(App); ChatClient.on('$.ready', () => { ReactDOM.render(<ChatComponent />, document.getElementById('root')); });
It may seem like we’ve added a lot of code here. But rest assured, all we’ve done is create a simple UI using the Material-UI library. However, note the components and the state we’re changing. We created a component called Message which will act as a dummy component to handle our chat messages. The other thing is the state that we’ve made in the App component, which allows us to clear the input of our chat when the user hits enter. The other variable we’ve stored in state is the messages array. This is to anticipate the messages that will come into our app and to re-render with every new message that we append to the array.
This part is fairly simple. All we’ll be looking at here is the two functions componentDidMount and sendChat. All of our logic for sending and receiving messages is going to be stored here.
react-chat-engine-app/src/index.js/src/index.js (Modified File)
import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import ChatEngineCore from 'chat-engine'; import { withStyles } from '@material-ui/core/styles'; import Card from '@material-ui/core/Card'; import CardActions from '@material-ui/core/CardActions'; import CardContent from '@material-ui/core/CardContent'; import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; import Button from '@material-ui/core/Button'; import Typography from '@material-ui/core/Typography'; import Input from '@material-ui/core/Input'; import opengraph from 'chat-engine-open-graph'; const now = new Date().getTime(); const username = ['user', now].join('-'); const ChatClient = ChatEngineCore.create({ publishKey: 'your-pub-key', subscribeKey: 'your-sub-key' }, { globalChannel: 'chatting' }); ChatClient.connect(username, { signedOnTime: now }, 'auth-key'); const styles = { card: { maxWidth: 345, margin: '0 auto', float: 'none', marginbottom: '10px' }, openCard:{ maxWidth: 200 }, openMedia: { height: 80, }, media: { objectFit: 'cover', }, container: { display: 'flex', flexWrap: 'wrap', }, }; class Message extends Component{ render () { return ( <div > { this.props.uuid }: { this.props.text } </div> ); } }; class App extends Component { constructor(props) { super(props); this.chat = new ChatClient.Chat(`BasicChatApp`); } sendChat = () => { console.log("Sending Chat"); } setChatInput = (event) => { this.setState({ chatInput: event.target.value }) } componentDidMount() { } handleKeyPress = (e) => { if (e.key === 'Enter') { this.sendChat(); } } render(){ const { classes } = this.props; return( <Card className={classes.card}> <CardContent> <Typography gutterBottom variant="headline" component="h2"> Messages </Typography> <div className={classes.root}> <List component="nav"> <ListItem> <Typography component="div"> { this.state.messages } </Typography> </ListItem> </List> </div> </CardContent> <CardActions> <Input placeholder="Enter a message" value={this.state.chatInput} className={classes.input} onKeyDown={this.handleKeyPress} onChange={this.setChatInput} inputProps=aria-label /> <Button size="small" color="primary"> Github </Button> <Button size="small" color="primary"> Exit </Button> </CardActions> </Card> ); } } const ChatComponent = withStyles(styles)(App); ChatClient.on('$.ready', () => { ReactDOM.render(<ChatComponent />, document.getElementById('root')); });
Let’s Analyze this code Function by Function.
Two things are happening here. First is the initialization of our ChatEngine object with a channel name. The second is creating a couple variables to track changes in our app, including the message that’s been typed and new messages coming into the application.
This function checks the state for whether the user has entered a message or not. In the case that they have pressed enter, the function will send a publish to the channel we’ve defined.
This method is used to retrieve all the users who have joined the chat room. This is used to populate the header section of the UI to display all the users that are currently present in the chat room.
This method is used to send the chat message from the app client. It is bound to the <input> box as well as the <button> element of the UI.
We now have a basic functional chat app built with React library. You can check out the GitHub repo for the complete code of this app. Now you can run the project on your machine!
Originally published at reactjs.chat.