Implementing React Hooks with Stream Chat
Tags: react, chat, programming, frontend
Published: 2020-01-09 03:37:38

React hooks, released in February 2019, have [huge benefits](https://reactjs.org/docs/hooks-intro.html#motivation) when implemented in your application. Whether you've used hooks before or are just learning, this post aims to show you just how simple it is to implement them with [Stream Chat](https://getstream.io/chat/).

## The Basics

Using hooks with Stream Chat is as simple as it sounds. Wherever you would regularly need local state or other React features, such as `componentDidMount`, is an example of somewhere you could implement hooks and therefore clean up your code.

For a basic overview of the many types of hooks, check out the [React Docs](https://reactjs.org/docs/hooks-overview.html). In a nutshell, there are 3 main use cases:

- [State Hook](https://reactjs.org/docs/hooks-overview.html#state-hook): `useState` adds local state to your component. This includes defining a current state variable, a function to update it, and a value to initialize that piece of state with.
- [Effect Hook](https://reactjs.org/docs/hooks-overview.html#effect-hook): `useEffect` gives you the power to perform "side effects" such as data fetching, subscriptions, or other DOM manipulation within a functional component.
- [Build Your Own Hooks](https://reactjs.org/docs/hooks-overview.html#building-your-own-hooks): By building your own hooks, you can reuse stateful logic between as many components as needed. It's important to use the same naming convention when creating your custom hook by always using the prefix `use` (such as naming your custom hook `useFriendStatus`) so that the React linter plugin is able to detect bugs.

There are a variety of other pre-made hooks you can use which are all laid out within the [Hooks API Reference](https://reactjs.org/docs/hooks-reference.html).

## Adding The State Hook

To keep it simple, we've just added a bit of functionality to the Demo App we've already provided for you through our demo page found [here](https://getstream.io/chat/demos/customers/). This demo chat app is made for users who need to communicate with their customer base. This demo only utilizes local state, so I'd added some lifecycle methods to it for us to refactor later on.

Here is the the [Codepen](https://codepen.io/whitneyburton/pen/yLypxjZ) we will start with today. As you can see, App is a class component that utilizes local state to determine whether the `Button` is set to open or closed. This will be an easy refactor to make the component functional with the `useState` hook!

_For now, we will ignore `componentDidMount` and `componentWillUnmount`, and just focus on adding `useState`. For that reason, those are both commented out for the time being._

### Original Class Component:

https://gist.github.com/whitneyburton/b8ef53702e7918b5b82907728d846cb9

In the process of moving from a class to functional component, there are a few things you need to do first.

- Import what you need from React - because we are using Codepen, we will access `useState` and `useEffect` using dot notation (i.e. `React.useState`) instead of with an import at the top of the file. In a typical project use case, you could just add the import to the top of the file: `import React, { useState, useEffect } from 'react';`
- Change App to be a functional component.
  `class App extends Component` turns into `const App = () =>`
  - You will also need to add `const` to the beginning of `toggleDemo` since we will no longer be able to access it using `this`.
- Remove the `render()`. Don't forget to delete both of the curly braces! :)

These are the few steps I always make sure I complete _before_ moving on to the hooks refactor so that they aren't forgotten about later on. Now our component looks like this:

https://gist.github.com/whitneyburton/72154fed23f6017bf0cdd852ae3df542

### Step 1: Functional Component

This will break as is because we are still using `constructor()`/`super()`/`this.state` as well as accessing our local state and functions with `this`. That's our next step - refactor the component to utilize the `useState` hook.

- First, change `constructor`/`super`/`this.state` into a hook: in order to accomplish this, you can start by simply removing the entire constructor, because you will be defining an entirely new variable using `useState`.
- After deleting the constructor, use the same key that you used in state as the new variable name. Since we were using `open` as the key with `true` as the initial value, and using on onClick on the button to toggle that boolean, here is what the hook will look like: `const [open, toggleOpen] = React.useState(true);`
  - `open` is the new variable name
  - `toggleOpen` is the function to update the value
  - `true` is the value we want to initialize the variable with, so we pass that into `useState`

https://gist.github.com/whitneyburton/5667c69376e1e3b9a456c525358fbdc2

### Step 2: Functional Component

Our refactor is almost complete. The last step is to update any references to `this`, `this.state`, and `this.setState` to reflect our new functional component structure and state hook. That will change a few areas:

- `this.state.open` is now: `open`
- `this.setState({ open: [true or false] })` is now: `toggleOpen([true or false])`
- `this.toggleDemo` is now: `toggleDemo`

Here's the final result:

https://gist.github.com/whitneyburton/2cc5037f4938ec4e03f0fbbbcfb1a746

### Cleaning It Up

To shorten your code up even more, you could switch the toggleDemo function into a quick ternary conditional since our `toggleOpen` update is so short:

https://gist.github.com/whitneyburton/341a0642e690e02828164932627feba6

### Overview

Overall, this small refactor took our component from _55 lines to 35_. Leveraging the `useState` hook allows us to quickly and easily set and update local state.

## Adding The Effect Hook

Now let's look into adding the `useEffect` hook! This means that we get to comment in our `componentDidMount` and `componentWillUnmount` lifecycle methods. For checking in on the functionality of the lifecycle methods, it's best to go back to our [original Codepen](https://codepen.io/whitneyburton/pen/yLypxjZ). Within that you'll notice:

- `componentDidMount` does two things:
  - First, it logs that the component rendered (this is for anyone who's new to React and just wants a reminder of when this fires)
  - Then, it utilizes Stream Chat's `sendMessage()` method (see the docs on this [here](https://getstream.io/chat/docs/js/#getting-started)) to demonstrate how you can send a pre-populated message to your customers when they join the chat.
- `componentWillUnmount` simply logs the number of state messages that you have in local state before unmounting the component. This shows you how you can check the number of local messages in your future app, and is generally just here to show you how to run clean up functions with `useEffect`.

### Step 1: Setup The Hook

Refactoring these two lifecycle methods to utilize the Effect Hook is easier than you might think. We will start by hashing out the `useEffect` method. Within CodePen, as stated above, you'll have to use dot notation to access it. This is what the refactor looks like to start:

```javascript
React.useEffect(() => {});
```

### Step 2: Refactoring componentDidMount

Whatever is usually put within your `componentDidMount` can just be plopped right into this function. So, in our example, we take the `console.log` and `channel.sendMessage` within `useEffect` like so:

```javascript
React.useEffect(() => {
	console.log('componentDidMount - rendered!');
	channel.sendMessage({
		text: 'Welcome to our customer chat with React Hooks tutorial!',
	});
});
```

That is all that you need to do to add the same functionality as `componentDidMount` with a hook! 👏

You can see this functionality in action with [this Codepen](https://codepen.io/whitneyburton/pen/WNbMOdG).

### Step 3: Refactoring componentWillUnmount

In order to add in logic which "cleans up" just before your component unmounts, all you have to do is return a function within your `useEffect`. For example, within our original `componentWillUnmount`, the only logic we performed was:

```javascript
console.log(
	`You have ${channel.state.messages.length} stored in local state. Goodbye!`
);
```

In order to add this effect to `useEffect`, just put that log into a function, and return it at the end of the effect, like so:

```javascript
return function cleanUp() {
	console.log(
		`You have ${channel.state.messages.length} stored in local state. Goodbye!`
	);
};
```

Easy as that! Now we've added all functionality back to our component, and the transition to a functional component with Hooks is complete. Here is the [complete Codepen](https://codepen.io/whitneyburton/pen/GRgyXdv) for your reference.

```javascript
React.useEffect(() => {
	console.log('componentDidMount - rendered!');
	channel.sendMessage({
		text: 'Welcome to our customer chat with React Hooks tutorial!',
	});

	return function cleanUp() {
		console.log(
			`You have ${channel.state.messages.length} stored in local state. Goodbye!`
		);
	};
});
```

## Summary

As we all know, the frameworks we work with daily are constantly changing. React is the perfect example of a powerful framework that is consistently coming out with their versions of the latest and greatest tech. Adding Hooks is a simple process and significantly cleans up your code. 

The great news is that there are no plans for React to remove classes, so you can keep the classes you are currently using, and just start implementing hooks within the smaller, and therefore more simple, components as you go. As the docs state, they are [100% backwards compatible](https://reactjs.org/docs/hooks-intro.html#no-breaking-changes). These are just the basics of hooks to get your feet wet and demonstrate how seamlessly they integrate with Stream Chat, which makes for an easy and exciting developer experience. 🙌