I’ve recently started a new project using React, and I began in my usual manner of mostly using class components. But, since I’ve decided to embrace Hooks, I’ve tried to convert my current classes into functional components.
Firstly, I tackled state, one of the key functionalities of React. Hooks make state much easier to declare by removing some of the previous boilerplates, including a constructor, which (in my opinion) makes the code much more readable.
The below code considers an input field that is used to dynamically filter an array by storing keystrokes into the component’s state:
This code uses the Class component:
export class SearchResults extends Component {
constructor(props) {
super.props;
this.state = {
inputFilter: ''
};
}
itemFilter = (event) => {
this.setState( state: {
inputFilter: event.target.value. toLowerCase()
});
};
...
Incorporating hooks in the code:
export const SearchResults = () => {
const [inputFilter, setInputFilter] = useState(initialState: '');
const itemFilter = (event) => setInputFilter(event.target.value.toLowerCase());
Note: for this to work we need to
import { useState }
from React.
Both of the codes above are dependent on the following input field:
<input type="search"
className="form-control"
placeholder={'Type here to filter...'}
onChange={itemFilter}
/>
Hooks allow you to give a functional component its own state, something that wasn’t previously available.
As noted, Hooks remove the previous boilerplate we’d need to create a component’s state. Now, we can define an inputFilter
entry by using the useState
method and passing it in a default value (here an empty string). Note, however, that we first need to import the useState
hook from the React library:
import React, { useState } from 'react';
When setting up our inputFilter
state entry, we also need to define a way to update that entry (here we’ve called this setInputFilter
). This is a function that is used to update our state.
In the code above, the initial state of inputFilter
is set to an empty string. When a user starts typing into the input field, the function itemFilter
is called. This then passes the typing event to the itemFilter
function, as a parameter (defined as event
), which is then translated into the actual characters typed by the user (denoted by event.target.value.toLowerCase()
)
So, our keystrokes have been passed to the function setInputFilter, and those characters are then used to set the value of our inputFilter element in our state. This is all we need to do to create and update our Hooks based state!
This example shows how to update a state that only has one value. However, an important scenario to consider is when the state element is an object or an array. With Hooks, using the updating function, we’ll be overwriting our state element rather than appending to it as would have been the case without Hooks. So, in this instance, if we want to update only a portion of an object or an array, we’d need to use the ES6 spread operator to maintain those other pieces of information.
So, in our application, if our state object is modified to include two separate filters, filter1
and filter2
like below, and we changed our setInputFilter
function to update only filter1
…
const [inputFilter, setInputFilter] = useState (initialState: {
filter1: '',
filter2: ''
});
const itemFilter = (event) => setInputFilter(value: {filter1: event.target.value.toLowerCase()});
…then this overwrites our previous value for filter2
…
> {filter1: "", filter2: ""}
> {filter1: "a"}
…and it’s lost. This can be very dangerous for losing elements of your state!
This wouldn’t have been the case without using hooks as setState({})
. Only amend the variable you wish to update.
Instead, we use the spread operator to maintain other pieces of state, only updating the value that we want:
const [inputFilter, setInputFilter] = useState (initialState: {
filter1: '',
filter2: ''
});
const itemFilter = (event) => setInputFilter(
value: {...inputFilter,
filter1: event.target.value.toLowerCase()
});
Now, both pieces of the state are maintained:
> {filter1: "", filter2: ""}
> {filter1: "a"}
As previously noted, I believe Hooks have lead to more readable code for creating and updating state. This makes it a lot more intuitive for new developers and also reduces the pain that some may have faced when their previously stateless functional component requires state.
But be careful when updating objects or arrays. Use the spread operator to maintain pieces of state that you didn’t want to alter!