loading...

React: Class Component VS Function Component with Hooks

danielleye profile image Danielle Ye Updated on ・3 min read

Class Component

Before React Hooks, when we want to create a dynamic component, we have to create a class component and use lifecycle methods to change states to make it reusable and encapsulate.

By creating an ES6 class, the class needs to extend React.Component with a render method in it, which will return the JSX markups. Also, we need to assign the initial state in the constructor with this.state. As an example, here we create a simple clock component with class. To make the clock working, we have to add Lifecycle Methods to our Class. We put elements into the DOM, it is called mounting in React. Same, We remove elements from the DOM, it is called unmounting. In React, mounting a component will invoke the following four build-in methods:

  • constructor()
  • getDerivedStateFromProps()
  • render()
  • componentDidMount()

More information please read from React Doc: Commonly used lifecycle methods

In our example, we set the initial state in the constructor and defined componentDidMount() to set the time every second. So the clock will update the state every second with the current time.

class ClockUsingClass extends React.Component {
    constructor(props) {
        super(props)
        this.state = { date: new Date() }
    }

    componentDidMount() {
        this.time = setInterval(() => {
            this.changeTime()
        }, 1000)
    }

    componentWillUnmount() {
        clearInterval(this.time)
    }

    changeTime() {
        this.setState({ date: new Date() })
    }

    render() {
        return (
            <div className="clock">
                <h1>Hello! This is a class component clock.</h1>
                <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
            </div>
        )
    }
}

Obviously we can see, for a class-based component, we need several steps to make it work with state-changing:

  1. Create a class with constructor(props) and render() methods.
  2. Set initial state with this.state statement in the constructor.
  3. Use this.setState() to update states.
  4. Use lifecycle methods like componentDidMount(), componentWillUnmount(), componentDidUpdate() etc. to change states

Function Component with hooks

Hooks are a new addition in React 16.8. The most useful feature of Hooks is that it allows using state without using class.

There are two most commonly used hooks: the state hook -- useState and the effect hook -- useEffect.

State hook allows you to add states in the function component. Instead of setting an initial state with this.state statement in the constructor, we can import { useState } from react, which will allow you to set the initial state as an argument. State hook will return a pair of values: the current state and a function that updates it. Usually, we will use useState like this:

    const [time, setTime] = useState(new Date())

Effect hook will get invoked with the first DOM updating. We can pass in a function in useEffect, and every time the DOM gets updated, the function in useEffect will get invoked too. Also, the effect hook allows you to pass in an array as the second argument, which contains all the dependencies that will trigger the effect hook. if any of the dependencies changed, the effect hook will run again. This feature provides us a more efficient way to make an Ajax request. Instead of making the request every time with DOM updates, you can pass in dependencies that only make the request while these values change.
useEffect can be used like:

    useEffect(() => {
        setInterval(() => {
            changeTime()
        }, 1000)
    })

So, here we re-write the clock we created above with hooks

const ClockUsingHooks = props => {
    const [time, setTime] = useState(new Date())

    const changeTime = () => {
        setTime(new Date())
    }

    useEffect(() => {
        const tick = setInterval(() => {
            changeTime()
        }, 1000)
        return () => clearInterval(tick)
    })
    return (
        <div className="clock">
            <h1>Hello! This is a function component clock.</h1>
            <h2>It is {time.toLocaleTimeString()}.</h2>
        </div>
    )
}

Summary

Comparing with these two ways to create a component, we can clearly see that hooks need less code and it is more clear to read and understand. Hooks give us a more efficient way to replace lifecycle methods.

Check out the repo to make a simple clock here

Posted on by:

danielleye profile

Danielle Ye

@danielleye

Front-end Developer from New York | Amateur Astronomer

Discussion

markdown guide
 

Function based components are harder to read in my opinion and large codebases tend to look like spaghetti when using function components. For less complex stuff, they seem to be a good way to go, for more complex things or larger codebases I rather stick to well structured class based components.

 

I was also thinking that but then I read this overreacted.io/how-are-function-co... and it changed my view about functional components , they seems more reliable than class components.

 

New to React (I've only read about it) so I may be wrong (and if I am, I'd like to know why) but I don't think you need the changeTime function in your hooks example, you can call setTime directly which would reduce it even further. Is it just a question of code style?

useEffect(() => {
const tick = setInterval(() => {
setTime(new Date())
}, 1000)
return () => clearInterval(tick)
})

 

It's good practice to decouple your code

 

I prefer to use class components, but it's personal preference more than anything. Class components and function components (with hooks) both have pros and cons.

One of the problems with class components is dealing with callback scope, i.e. what "this" references, but that can be handled easily these days by attaching a simple decorator to the callback methods. This isn't an issue for function components.

One of the problems with function components (with hooks) is every time the component is rendered, nearly every function in the component (either top-level or passed into a hook) has to be recreated, and that will cascade down through the hooks you use. That can end up being quite painful for performance and/or the garbage collector. This isn't an issue for class components.

You can do almost everything with class components as you can with function components, and vise-versa, so which one people decide to use is personal preference and/or an architectural design decision. I don't believe one is significantly worse than the other.

 

So it seems it is pretty much a preference. I find classes better as they are structured and I find it easier to arrange my code. Also when I have to look back I find it easier to navigate.

 

Hey Danielle! Had a quick question for you. Now that hooks have brought state to functional components, beside concision why would someone use a class component over a functional component?

 

Hi Tian,
In my understanding, class components can be replaced by functional components with hooks. But for some old projects, they are still using class instead of rewriting the whole project.
Also as react team said, they won't stop supporting for class but they suggest trying hooks on new projects. Check this on react docs 👉🏻: reactjs.org/docs/hooks-intro.html#...

 

How can we pass state properties between two functional components?

 

Nice and clear article.Thanks a lot for sharing :)

 

Why would someone use class-based components over functional components right now?

 

It seems that in the hooks example you didn't clear the interval. Why is that?

 

Hey Raul, thanks! You are right and it is a good point! I updated the code. It is a valid concern when the app is not server-side rendered.

 

Why does the useEfrect return the clear interval function? How does it work??