Hooks are upcoming features in React and are currently available in version 16.7.0-alpha.2. The hook can be used by installing the above version.
npm i react@next react-dom@next
So, what are Hooks?
Hooks let you use React features without writing classes, they are functions that let you ‘hook into’ React state and life cycles from the functional component.
Note : Hooks don’t work inside classes.
Below we will see a simple example of the counter using both class and functional components with Hooks to grasp the concept of Hooks.
First, we will see the code for a counter component using class.
import React, { Component } from 'react'
class App extends Component {
constructor(props){
super(props);
this.state = {
count:0
}
}
increaseCount = () => this.setState((prevState)=>({count :prevState + 1}));
render() {
const {count} = this.state;
return (
<div>
<p>Number of clicks: {count} </p>
<button>Increase Count</button>
</div>
)
}
}
export default App;
Now, here is the code for a counter component using a functional component with Hooks.
import React, { useState } from 'react;
function App() {
const [count, setCount] = useState(0);
const increaseCount = () => setCount(count + 1)
return (
<div>
<p>Number of clicks: {count}</p>
<button>Increment Count</button>
</div>
);
}
export default App;
The first noticeable difference you’ll probably see is how much cleaner the code is for functional components with hooks compared to a class component.
In our class component, we have initialized a count state in the constructor and a function increaseCount in which we are using this.setState to increase the count state when we are clicking on the button.
While in our functional component, we have used the useState hook, which returns a pair of values such as a current state and a function that updates it. And it takes only one argument, which is the initial state. That’s why we write
const [count,setCount] = useState(0);
where the count is a current state variable, which is similar to this.state.count
and setCount is the function which updates the state, which is similar to this.setState
and 0 is the initial value of the count state.
The square brackets used above are array destructuring, which is a JavaScript syntax. So, instead of using count and setCount, we could have used any other variable name such as
const [a, setA] = useState(0);
We can also declare multiple state variable in a single component.
const [a, setA] = useState(0);
const [str, setStr] = useState('test');
const [count, setCount] = useState(1);
const [obj, setObj] = useState({foo:'',boo:''})
Note from React documentation about the implementation of multiple state variables.
You don’t have to use many state variables. State variables can hold objects and arrays just fine, so you can still group related data together. However, unlike
this.setState
in a class, updating a state variable always replaces it instead of merging it.We provide more recommendations on splitting independent state variables in the FAQ.
Now, we will look into another hook named as useEffect,
which is used for performing side effects. It is like a combined componentDidMount
, componentDidUpdate
, componentWillUnmount
. Below is the implementation for useEffect
.
import React, { useState, useEffect } from 'react;
function App() {
const [width, setWidth] = useState(window.innerWidth);
const resizeWidth = () => setWidth(window.innerWidth);
useEffect(()=> {
window.addEventListener('resize',resizeWidth);
return () => {
// this will be used for clean up, same as componentWillUnmount
window.removeEventListener('resize',resizeWidth);
}
},[]
//empty array will ensure that useEffect will run only on mount
and unmount
)
return (
<div>
<p>Width : {width}</p>
</div>
);
}
export default App;
Rules of Hooks
- Hooks must be called only at the top level. Calling Hooks inside loops, conditions, or nested conditions is a BIG NO! as Hooks rely on call order. The explanation for above is given in: https://overreacted.io/why-do-hooks-rely-on-call-order/
- Hooks must be called from React functional component or from custom hooks (will read about it in the next section). Hooks must not be called from a regular JavaScript function.
Custom Hooks
We can build our own Hooks, the advantage of building our own hook is that we can put shareable logic into reusable functions. A custom hook must start with ‘use’ so that it can automatically check for violations of Rules of Hooks, this convention is very important. For example, if we need the width state variable in the above code, in more than one component, we can convert it into custom hooks. Below we have made our useResizeWidth custom hooks.
function App() {
const [count, setCount] = useState(1);
const width = useResizeWidth();
const increaseCount = () => setCount(count + 1);
return (
<React.Fragment>
<div>
{count} Width: {width}{" "}
</div>
<button onClick={increaseCount}>Increment Count</button>
</React.Fragment>
);
}
function useResizeWidth() {
const [width, setWidth] = useState(window.innerWidth);
const resizeWidth = () => setWidth(window.innerWidth);
useEffect(() => {
window.addEventListener("resize", resizeWidth);
return () => {
window.removeEventListener("resize", resizeWidth);
};
}, []);
return width;
}
From the above example, we can see our useResizeWidth() custom hook is a JavaScript function.
CodePen : https://codepen.io/bhavya2995/pen/pqdror
Reference : https://reactjs.org/docs/hooks-intro.html