Refactoring a Class Component to a Functional Component in React, with Hooks

Hooks were introduced a little more than two years ago, when Facebook released React 16.8 in February 2019. Many software engineering students still learn React workflows using class components before shifting over to hooks, and the transition can be a little confusing.

Here’s what an incredibly barebones class component with state and a fetch call might look like.

Class Component

import './App.css';
import React, {Component} from 'react'
import CardContainer from "./components/CardContainer"

class App extends Component {

  state = {
    jokes: []
  }

  componentDidMount = () => {
    fetch('http://localhost:3000/jokes')
      .then(response => response.json())
      .then(jokes => this.setState({jokes}))
  }

  render() {
    return (
      <div className="content-container">
        <CardContainer jokes={this.state.jokes} />
      </div>
    );
  }
}

export default App;

The very same result can be achieved using a functional component, with two of React’s most prominent hooks: useEffect() and useState(). The main differences from a surface-level standpoint are:

  1. “class App extends Component{}” becomes “function App(){}”.
  2. You don’t need to wrap the return statement in a render function.
  3. You no longer need to use “this.” syntax, such as this.state or this.myFunction.
  4. useState replaces state = {} and this.setState().
  5. useEffect replaces componentDidMount, with one huge caveat: do not forget the dependency array!
  6. useEffect and useState must be imported, while you can drop the Component import.

Functional Component

import './App.css';
import React, { useState, useEffect } from 'react'
import CardContainer from "./components/CardContainer"

function App(){

  const [jokes, setJokes] = useState({})

  useEffect(() => {
    fetch('http://localhost:3000/jokes')
    .then(response => response.json())
    .then(jokes => setJokes(jokes))
  },[])

  return (
    <div className="content-container">
        <CardContainer jokes={jokes} setJokes={setJokes}/>
    </div>
  );
}

export default App;

If using useEffect for a fetch call, do not forget that empty dependency array. Leaving it out will result in an infinite loop that hits the API thousands of times in mere minutes. The dependency array allows you to specify conditions which, when met, tells useEffect to execute a re-render. By providing an empty array, you’re telling useEffect to run only once upon mounting, similar to the functionality of componentDidMount. I’ve bolded it below for emphasis, as forgetting this step is one of the most common errors fledgling React programmers make. This DEV blog post by Max Rozen offers more detail about useEffect and its dependencies, if you choose to go further down the rabbithole.

 useEffect(() => {
    fetch('http://localhost:3000/jokes')
    .then(response => response.json())
    .then(jokes => setJokes(jokes))
  },[])

The useState hook, in essence, increases readability and decreases potential confusion. You can pass state down using a variable name of your own choosing—in this case, jokes is assigned an array of joke objects. You can change this state directly using the associated setJokes function, which operates the same as this.setState.

I hope this simple example helps a future React student understand the differences between a class component and a functional component, as well as increases their familiarity with their two new best friends: useEffect and useState! Happy coding.

Advertisement

Published by G. Jeff Golden

Mountaineer, dog owner, Carolina Panthers fan and outdoor writer based in Arvada, Colo.

One thought on “Refactoring a Class Component to a Functional Component in React, with Hooks

  1. This is helpful to have. I landed here looking for a more complex use case: the bloated Component – one with multiple render statements. A nice follow-up to this post on creating functional components would be to deconstruct one that’s more complex. And do it all in vanilla JS.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: