Classes can be a large barrier to learn React, says React team. They don’t minify very well and they make hot reloading unreliable. With React Hooks, you don’t need to convert a function component into class component. You can use state and lifecycle methods in the function component.
Okay, but what are hooks really?
They are functions that let you “hook” into React internal state and lifecycle features from function components
Great! How do I do that?
First, Update your React and React DOM dependency in your project. Hooks are freshly released on React 16.8.0 today!
npm install --save react@^16.8.0 react-dom@^16.8.0
Now let’s take a look on the useState
hook. Here is the demo:
useState
hook
We need to have a simple class component with state for comparison. The easiest example I can imagine is of an input form:
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = { value: '' };
}
handleChange = event => {
this.setState({ value: event.target.value });
};
render() {
return (
<form>
<label>
Name:
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
/>
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Now let’s rewrite it using useState
hook. We’ll import it from react
package so we don’t have to write React.useState
all the time.
import React, { useState } from 'react';
Now change our NameForm
into a function component
function NameForm(props) {}
useState
hook takes one argument, which is the initial state, and it returns two values: the current state and a function that can be used to update the state. You can replace the state initialization in the constructor:
this.state = { value: '' };
into this:
function NameForm(props) {
const [value, setValue] = useState('');
}
Notice the use of square brackets when state variable is declared. This is the ES6 “array destructuring” syntax, and it means we’re assigning the first value returned by useState to value
and the second value to setValue
.
So this means we have a state named value
and we can update it by calling on setValue
function. Let’s use it on our render method:
function NameForm(props) {
const [value, setValue] = useState('');
return (
<form>
<label>
Name:
<input
type="text"
value={value}
onChange={event => setValue(event.target.value)}
/>
</label>
<input type="submit" value="Submit" />
</form>
);
}
Onchange
props no longer call a handleChange
method, instead we have an arrow function that will call setValue
function, which update our state
. Oh, and unlike this.setState
in the class component, updating a state variable using hooks always replace it instead of merging it
Having multiple states?
Then call on useState
as many times as you need.
function SimpleForm(props) {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [age, setAge] = useState('');
return (
<form>
<label>
First Name:
<input
type="text"
value={firstName}
onChange={event => setFirstName(event.target.value)}
/>
</label>
<label>
Last Name:
<input
type="text"
value={lastName}
onChange={event => setLastName(event.target.value)}
/>
</label>
<label>
Age:
<input
type="number"
value={age}
onChange={event => setAge(event.target.value)}
/>
</label>
<input type="submit" value="Submit" />
</form>
);
}
And that’s it with useState
hook, really!
Setting initial state from props
Oh, it’s so easy!
function SimpleForm(props) {
const [firstName, setFirstName] = useState(props.firstName);
const [lastName, setLastName] = useState(props.lastName);
const [age, setAge] = useState(props.age);
//...
}
ReactDOM.render(
<SimpleForm firstName="JOHN" lastName="Edward" age={30} />,
document.getElementById('root')
);
Can I use object in state?
Sure! Just as class state
can accept object or array, useState
can have them as well. But to make it work, let’s add name props to your input elements. We also use spread properties to update our state.
function SimpleForm(props) {
//create object state
const [form, setForm] = useState({
FirstName: '',
LastName: '',
age: '',
});
const handleChange = event => {
// use spread operator
setForm({
...form,
[event.target.name]: event.target.value,
});
};
return (
<form>
<label>
First Name:
<input
type="text"
name="firstName"
value={form.firstName}
onChange={handleChange}
/>
</label>
<label>
Last Name:
<input
type="text"
name="lastName"
value={form.lastName}
onChange={handleChange}
/>
</label>
<label>
Age:
<input
type="number"
name="age"
value={form.age}
onChange={handleChange}
/>
</label>
<input type="submit" value="Submit" />
</form>
);
}
What about array?
This one’s a bit unusual, but yes, just like in class state
. We’ll use concat on array update.
function SampleArrayState(props) {
//create array state
const [nameArray, setNameArray] = useState(['Carl']);
const updateArray = () => {
setNameArray(nameArray.concat('John'));
};
return (
<React.Fragment>
<button onClick={updateArray}>Click me!</button>
<div>{nameArray.toString()}</div>
</React.Fragment>
);
}
And Boolean?
Got you covered here:
function SampleBooleanState(props) {
const [show, setShow] = useState(true);
const visibility = show ? 'visible' : 'hidden';
return (
<React.Fragment>
<h1 style={{ visibility }}>useState Hook is awesome!</h1>
<button
onClick={() => { setShow(!show) }}
>{`${show ? 'Hide' : 'Show'} the Header!`}</button>
</React.Fragment>
);
}
The rules of hooks
The important thing to remember is that hooks don’t work in a class component. They are made for function components.
- Don’t call hooks from inside nested function, loops or conditionals.
- Don’t call hooks from regular JavaScript function.
- Dont’ refactor your old code.
Conclusion
The useState
hook enables function components to access React’s internal state and update it. The state can be any data type: string, number, boolean, array, or object. useState
accept one argument: the initial data, and it returns an array of two values: the current state value and the function/ method that can be used to update the state.
There are more than just useState
hook, but let’s cover each hook in their own single post.
Here’s a list of all built-in hooks (yes, you can write a custom hook!) available as of this writing. I’ll be covering them in the next posts!
Until next time!