The last couple of months have been anything but ordinary in the React ecosystem. It all started at the React Conf 2018, where React development team announced a new feature, which they named React Hooks. If this feature gets accepted by the community, it is going to be a huge breakthrough and it is going to change the way developers perceive and write React components. Having that in mind, let’s talk about React hooks and what they are bringing to the React community.
What are React hooks?
React hooks are actually JavaScript functions, available as of React version 16.8, which let you “hiook into” React state and lifecycle methods. By convention, those functions are named use{Something} (where “Something” explains what the hooks are used for). A couple of those hooks (like useState, useEffect, useContext, etc.) are included in the React package, and all you have to do is import them into your component and start using them. If there is no hook available for the task you need to accomplish, you’re free to write your own hooks and use them as you will, as long as you follow the naming convention and the two basic rules of using hooks:
- ONLY CALL HOOKS AT THE TOP LEVEL! – which means you should only use hooks in your top-level function, and not in any kind of conditions, loops or any nested functions.
- ONLY CALL HOOKS FROM REACT FUNCTIONS! – which means you are only allowed to use the hooks in React component functions and custom hooks.
But what makes React hooks so special? We could already use state, lifecycle methods, context etc., long before hooks. So why would we need them?
Why React hooks?
React hooks are meant to change the way we write React components. As we all know, there are two kinds of components in React:
- stateful (also called smart components or containers), which always had to be class-based components, because state, lifecycle methods and couple of other methods were only available in class-based components;
- stateless (also called pure, dumb or presentational components), which could either be class-based or functional components;
With the addition of hooks, this concept changed for good. Now, with the help of the hooks, you can have most of the features in your functional components that before the release of the hooks were exclusively available for class-based components. And that allows us to write our ♥whole application with functional components only! As the React team said, they got the motivation to create hooks by 3 problems faced by most React developers: stateful logic is hard to reuse and leads to complex nesting (components, providers, consumers, higher order components etc.); some components are becoming really huge and hard to manage, and sometimes it’s really hard or even impossible to split them into smaller components; and JavaScript classes are confusing for people (just think about the usage of “this” in JavaScript classes). Hooks are efficiently dealing with those problems. But enough with the talking, let me show you how this really works in practice:
import React, {Component} from 'react';
import AgeContext from '../context/ageContext';
import './Card.css';
class ClassCard extends Component {
constructor(props) {
super(props);
this.state = {
firstName: '',
lastName: '',
}
this.handleFirstNameChange = this.handleFirstNameChange.bind(this);
this.handleLastNameChange = this.handleLastNameChange.bind(this);
}
componentDidMount() {
this.setState({
firstName: 'John',
lastName: 'Doe',
})
}
componentWillUnmount() {
this.setState({
firstName: '',
lastName: '',
})
}
handleFirstNameChange(e) {
this.setState({
firstName: e.target.value,
})
}
handleLastNameChange(e) {
this.setState({
lastName: e.target.value,
})
}
render() {
return (
<AgeContext.Consumer>
{context => (
<div className='Card'>
<label className='Label'>First Name:</label>
<input
className='Input'
placeholder='Enter your first name:'
value={this.state.firstName}
onChange={this.handleFirstNameChange}
/>
<hr />
<label className='Label'>Last Name:</label>
<input
className='Input'
placeholder='Enter your last name:'
value={this.state.lastName}
onChange={this.handleLastNameChange}
/>
<hr />
<label className='Label'>Age:</label>
<label className='Label'>{context.age}</label>
</div>
)}
</AgeContext.Consumer>
);
}
}
export default ClassCard;
Here we have a simple class-based component in React. In a real world application, you would have tens or hundreds of them, and some would be much bigger and much more complex than this. The component needs to have a local state, so it must be class-based. Or, so it was, until React 16.8 and the introduction of hooks.
import React, {useState, useEffect, useContext} from 'react';
import AgeContext from '../context/ageContext';
import './Card.css';
export default function FunctionCard() {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const ageContext = useContext(AgeContext);
useEffect(() => {
setFirstName('John');
setLastName('Doe');
return () => {
setFirstName('');
setLastName('');
}
}, []);
function handleFirstNameChange(e) {
setFirstName(e.target.value);
}
function handleLastNameChange(e) {
setLastName(e.target.value);
}
return (
<div className='Card'>
<label className='Label'>First Name:</label>
<input
className='Input'
placeholder='Enter your first name:'
value={firstName}
onChange={handleFirstNameChange}
/>
<hr />
<label className='Label'>Last Name:</label>
<input
className='Input'
placeholder='Enter your last name:'
value={lastName}
onChange={handleLastNameChange}
/>
<hr />
<label className='Label'>Age:</label>
<label className='Label'>{ageContext.age}</label>
</div>
);
}
Above we have the same component like before, with the same behavior, but this time it is written as functional component, with the help of React hooks. The difference is that the function component is much more compact, has less lines (51 compared to 72, and the difference is pronounced even more on larger components), and also we are not using “this” (which is a big benefit by itself).
Conclusion
React hooks are a fairly new feature, introduced with React 16.8 just a couple of months ago, but their future looks very promising. They bring many benefits to the React developers, like the ability to create functional stateful components, the ability to extract stateful logic from a component and create custom hooks in order to be able to reuse it across components, the components become less complex, the developers write less lines of code, and all the problems that come up from JavaScript classes and the use of “this” are gone. The best part of this is that this is not a breaking change. Both class-based and functional-based components will be developed and supported by the React team in future, and they are also compatible with each other, so it’s up to the developers to choose which of those (or a combination of both) better fits their needs.
If you want to learn more about React hooks, you can start by reading the official React documentation here: https://reactjs.org/docs/hooks-intro.html.