React: Hooks in functional components

Posted on July 20th 2020 in React by Pim Debaere.

React: Hooks in functional components

As told in a previous post, nowadays you can use Hooks in React, allowing you to use state and lifecycle methods without problems. Read further to know how.

State Hook

A Hook is a special function that allows you too hook into React. The most commonly used one is the State Hook, because a lot of components use state to hold and update data. Let's start with a small example of a stateful component.

1
2
3
4
5
6
7
8
9
10
11
12
13
// stateful component
import React from 'react';

class Album extends React.Component {
    constructor(props) {
        super(props);
    
        this.state = {
            title: 'Strange Days',
            artist: 'The Doors'
        };
    }
}
Fig. 1 – Example of a stateful component.

If we want to do the same, but stateless, we get the functional component below that's using the useState Hook.

1
2
3
4
5
6
7
// functional component, using a Hook
import React from 'react';

function Album() {
    const [title, setTitle] = useState('Strange Days')
    const [artist, setArtist] = useState('The Doors');
}
Fig. 2 – Example of a functional component with Hooks.

In the above example you can see that the declaration of state has been replaced with the useState Hook. Behind the scenes the same happens: the state variables – "title" and "artist" in this case – are being declared and initialized. The argument that is passed in useState is used as default value of the variable. Most likely this will be an empty string, true/false

The return value of useState is an array holding two values: de current state of the variable and an update function. These are the same as this.state.title and this.setState in a stateful component. I also want to point out that the names of both variables in the return value can be chosen freely; it can be something like const [title, modifyTitle] as well – although the general naming convention is with set.

Read and update

Now that we know how to create a state variable, the only question left is how to use it. The example below speaks for itself.

1
2
3
4
5
6
7
8
// stateful component
// read
<p>My favorite album is "{this.state.title}" by {this.state.artist}</p>

// update
onChange = event => {
  this.setState({title: event.target.value})
}
Fig. 3 – Lezen en bijwerken van een state variable (stateful).
1
2
3
4
5
6
7
8
// functional component
// read
<p>My favorite album is "{title}" by {artist}</p>

// update
onChange = event => {
  setTitle(event.target.value)
}
Fig. 4 – Lezen en bijwerken van een state variable (functional component).

Lifecycle methods

Functional components don't have lifecycle methods by default, but luckily there's a Hook: useEffect. useEffect will be called automatically when one of the given variables changes. A perfect replacement for componentDidMouunt and componentDidUpdate!

Both examples below will write the given title to the local storage when the input field changes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// stateful component
class Album extends React.Component {
    constructor(props) {
        super(props);
        
        this.state = {
          title: localStorage.getItem('title') || ''
        };
    }

    componentDidUpdate() {
        localStorage.setItem('title', this.state.title);
    }

    onChange = event => {
        this.setState({ value: event.target.value });
    };

    render() {
        return (
            <input type="text" value={this.state.title} onChange={this.onChange} />
        );
    }
}
Fig. 5 – Stateful component die gebruik maakt van didComponentUpdate.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// functional component
function Album() {
    const [title, setTitle] = useState(localStorage.getItem('title') || '');

    useEffect(() => {
        localStorage.setItem('title', title);
    }, [title]);

    onChange = event => setTitle(event.target.value);

    return (
        <input type="text" value={title} onChange={onChange} />
    );
}
Fig. 6 – Functional component die gebruik maakt van useEffect.

Thanks to Hooks, there is nog longer any reason to rework your components into functional components – with the exception perhaps of very complex components. To learn more about Hooks, you can read the official documentation.