React useState Hook

An introduction on how to use useState Hook in your React application

Thursday, October 21, 2021

hook in a terrible state

What is a React hook?


From the React's official documentation

Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class.

What does it mean?

To give you more context, before React v16.8, we can only enable a component to have a state and manage it if a component is created using a class.

.jsx
1234567891011121314151617181920class MyClassComponent extends React.Component { constructor(props) { super(props) this.state = {attribute: 'some value'} this.handleStateChange = this.handleStateChange.bind(this) } handleStateChange(e) { this.setState({attribute: e.target.value}) } render() { const {attribute} = this.state return <> <div>State: {attribute}</div> <input onChange={this.handleStateChange} value={attribute} /> </> }}
Link to Codepen

A Functional component is mainly used as a dumb component where the decision on how to render it differently is derived from the props it will receive from its parent component.

.jsx
123456function MyFunctionalComponent ({attribute, onChange}) { return <> <div>State: {attribute}</div> <input onChange={onChange} value={attribute} /> </>}

If you notice, we need fewer keystrokes to create a functional component, but the problem is it would not be reactive to state changes. Let's try to mimic all the class component behaviors to our function component.

.jsx
123456789101112function MyFunctionalComponent () { let state = {attribute: 'some value'} const handleStateChange = (e) => { state = {attribute: e.target.value} } return <> <div>State: {state.attribute}</div> <input onChange={handleStateChange} value={state.attribute} /> </>}
Link to Codepen

You can modify the component all day long; however, it won't react to state changes.


What if we can have the simplicity of the functional component and still have the ability to react to state changes?


React hooks to the rescue!


As per the title of this blog, I will only discuss useState which is the solution related to our previous problem. I will discuss the other types in another blog.


Here are some ways on how to can create a useState hook:

.jsx
123456789101112131415161718import React from 'react' ...React.useState()React.useState(true)React.useState([])... OR import {useState} from 'react' ...useState()useState('default value')useState({a: 1})useState(() => 'value returned from a function')...

As mentioned in the above examples, here's what you can pass in a useState as an argument:

If you passed one, it would serve as the default state for that instance, else default state will be null


When useState is invoked, it will return an array. The first element is the state and the second element is the state updater.

.jsx
123const stateArray = useState()stateArray[0] // statestateArray[1] // state updated

A simpler and more readable way to access the state and the state updater is by using the array destructing assignment. The convention for the second element is to prepend it with set, then make it camelCase.

.jsx
1const [state, setState] = useState()

Let's replicate the behavior of the class component in a function component using a useState hook.

.jsx
123456789101112function MyFunctionalComponent () { const [attribute, setAttribute] = React.useState('some value') const handleStateChange = (e) => { setAttribute(e.target.value) } return <> <div>State: {attribute}</div> <input onChange={handleStateChange} value={attribute} /> </>}
Link to Codepen

Hooray! We just created a much simpler stateful component using useState. Let's break down what happened.


We created a new state with a default value of some value. attribute will serve as the variable containing the default and future value of this hook. setAttribute will be the function that can modify our state

.jsx
1const [attribute, setAttribute] = React.useState('some value')

We define a method that will handle the change event from our input element.

.jsx
123const handleStateChange = (e) => { setAttribute(e.target.value)}

We display the state and attach handleStateChange to onChange event.

.jsx
1234return <> <div>State: {attribute}</div> <input onChange={handleStateChange} value={attribute} /></>

You can also simplify further if you want

.jsx
1<input onChange={e => setAttribute(e.target.value)} value={attribute} />

Does it mean we should not use a class component ever again?

I always use the functional component approach, but if I'm working on a very old codebase where there's no way to migrate to the newer version, I will use a class component. Also, it is written in the React documentation that There are no plans to remove classes from React. However, there are some use cases like when using Inheritance, creating Error Boundary, explicit lifecycle methods, and such that cannot be directly done using a functional component, although there are many workarounds to apply the expected behavior.



Conclusion

useState will simplify how we can create a component. Less code means fewer bugs(if used properly) and is easier to read, resulting in better maintainability.