React Hooks is a new way to build your React Components. React Hooks are nothing but just a functional component. And these components have extra features and capabilities which belonged exclusively for class-based components so far. React Hooks makes it possible to take stateful logic out of our component to reuse it in another component which was difficult in class-based components, that introduced complex render props and higher order component design patterns.
Yes, React Hooks makes it possible to have access to state logic and React’s lifecycle methods in functional components.
Using just Presentational and Class components in React sound so 2018. React’s latest Stable version [16.8] supports React Hooks. In this article, we will have a brief look at some of the main features of React Hooks.
As mentioned earlier, React Hooks can have state logic and lifecycle methods in it. Basically, Classes can have instances to it. Due to which we havethis
as an instance variable. We can accessthis
from any methods within the class.We cannot accessthis
in functional components, as they do not have an instance variable associated with it. So this should make you clear that there cannot be anythis.setState
which we had in Class Components. This leads us to the question.
It is with the help ofuseState
Hook we maintain our State logics inside our Component. We will also be seeing aboutuseRef
which helps in providing a reference to a JSX element or a callback .useEffect
for lifecycle methods. We will see about those in the following example by creating a Timer.
import React, {useState, useRef, useEffect} from 'react';
const Timer = (props) => {
const [time, setTime] = useState(new Date().toLocaleTimeString());
const secondsPassed = useRef(0);
useEffect(() => {
const timeout = setTimeout(() => {
const date = new Date()
secondsPassed.current = secondsPassed.current + 1;
setTime(date.toLocaleTimeString());
}, 1000);
return () => {
clearTimeout(timeout);
}
}, [time]);
return (
<div>
<div>{time}</div>
<div>{secondsPassed.current}</div>
</div>
)
}
export default Timer;
Output:
[Line 4] As I mentioned earlier,useState
helps in creating a state variable. useState is a function that returns an array of two elements
useState
takes one parameter as the argument which is the initial state value.[It can be of any type]I have created a state variable calledtime
(In the above example).
To modify its state I have usedsetTime()
.In SetTime I have pass the new value in the argument. So, once the new time is set[line 11] it re-renders. As it is a functional component it executes everything from the beginning for every render.
How is it Different from Class based state variables?
setTimer
in the above example).this.setState
in class components, does not behave this way. While setting state usingthis.setState
, if any existing properties are missed, current properties are merged with previously existing properties. Now, this explains why is it better to have independent state variables as mentioned in point 1.[Line 5] This hook helps in maintaining References. Yes, I know what you are getting at. I said functional components cannot have references and now I am talking about them having references in it.
In our functional components, all variables that we create, cannot be made as State variables . The logic should remain persistent sometimes. Inspite of any render that occurs to the component it should remain intact.useRef
Hook helps us in the above scenario.useRef
is similar to havingthis
in class Components.
I have a defined a referencesecondsPassed
, in the example above.secondsPassed
gives the number of seconds elapsed after starting the timer. And to update it [in line 10] I have access done it likesecondsPassed.current = <%new value%>
. This helps in immediately binding the new value to the reference.
So how doesuseRef
Hook differ from class-based refs?
As you can see from my example,
useRef
references are not limited to applying it only as a reference to JSX elements like how we do it in case of Class-based components.useRef
can also be used to store values similar to having an instance variable and to persist logics between multiple renders.In my opinion, React team might have understood that having a hell lot of Lifecycles with complex names makes it hard for any beginners to start with React in spite of the benefits that it offers.I would sayuseEffect
have reduced the burden of remembering the lifecycle names. Bye Bye Weird lifecycle Names.
However, withuseEffect
, we can declaratively inform React to what it should do.
In my example above, line 7 we have declareduseEffect
.
useEffect
React hook in our component.useEffect
Hook to trigger a timeout which on every second resets the state value of time. Then, we update the secondsPassed reference within it. As we need to reapply this effect (i.e) rerun this function on render only if the state variable time changes. So we mention that to React by creating an array with just time variable in it.[line 16].We can achieve the following lifecycle methods withuseEffect
hook.
componentDidMount
:useEffect
with empty array as second argument.componentDidUpdate
:useEffect
with the second argument as an array that contains a list of variables to listen to.componentWillUnmount
:useEffect
with the first argument as a function that returns a function(this returned function should have unmount logics).And the second argument as an empty array.render
: The entire content inside it is rendered as it is a functional component.
This Hook serves as an Alternative toshouldcomponentUpdate
.
import {useMemo} from 'react';
//...some code
const memoizedValue = useMemo(() => {
findPrimeNumbersinRange(a, b)
}, [a, b]);
//...some code
useMemo
takes the function and can return any value to memoize. Memoization is nothing but caching values.
The values ofa
andb
(In the above example) are used to find the PrimeNumbers between the given range [from a to b]. And we know, calculating Prime numbers is an expensive task especially when the numbers are larger.
This optimization helps to avoid expensive calculations on every render.
useMemo
checks from its second argument if a or b’s value has been changed. Values that are cached previously are used otherwise So if its values do not change then there is no rerun of the logic inside the function.
Note: Only use React hooks specific API in the top-level of your component and not inside return or inside any other function[only on the root level].
Thus, we have seen some of the important Hooks in React and have understood how we can leverage them in our application. Also, we have seen how Hooks Effects maps to Lifecycle components and how using Refs allows us to store values as well, apart from storing reference to DOM element. Here, we can extract the effect and make it an independent hook (custom hook) and can reuse the stateful logics across components.
There are other Hooks APIs like useContext, useReducer and useCallback. To know more about them visit React Docs