DEV Community

Cover image for Implementing React Hooks with Stream Chat
Nick Parsons
Nick Parsons

Posted on • Originally published at getstream.io

Implementing React Hooks with Stream Chat

React hooks, released in February 2019, have huge benefits 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.

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. In a nutshell, there are 3 main use cases:

  • 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: 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: 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.

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. 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 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. 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) 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:

React.useEffect(() => {});
Enter fullscreen mode Exit fullscreen mode

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:

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

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.

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:

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

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:

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

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 for your reference.

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!`
        );
    };
});
Enter fullscreen mode Exit fullscreen mode

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. 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. πŸ™Œ

Top comments (0)