React Hooks are the latest additions to the React block (React version 16.8) as they bring along great capabilities to revolutionize and energize, the feeble and simple looking Functional components.
As we know, React supports two types of components, namely, Functional and Class. The important difference between them is that we cannot handle the state or any life cycle methods in Functional components.
Hooks provide a way of adding these capabilities and many others to REACT’s Functional components.
In this blog, we will find some good ways and good reasons to put React hooks to use.
Visit our REACT Technology Page to know how WalkingTree Technologies helps unlock the true potential of REACT.
Contact us today for more information on our application development services in REACT.
Reusing Stateful Logic and Avoiding Duplication
In the class components, whenever we need the logic relating to a manipulating state, or we need to fetch data from API, etc. , we usually make use of lifecycle events while the logic will be specific to the class component.
Let us consider an example of fetching user data and presenting the same on the UI.
We will handle the user data in our application state.
In a class component we will do the following:
- Initialize the state to an empty array in the constructor
- Make the API call using axios in componentDidMount() to fetch the data
- If there is any update in the search filter, the API call will be handled again in the componentDidUpdate() lifecycle event handler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
class UsersClass extends Component { state = { users: [] }; componentDidMount() { console.log("componentDidMount called"); axios.get('https://hooks-demo-a6d15.firebaseio.com/users.json') .then(res => { const users=[]; for (const key in res.data){ users.push({ id: key, name :res.data[key].name, age: res.data[key].age, interests: res.data[key].interests}); } this.setState({ users } ); }) .catch(err => { console.log(err); }); } render () { const users = this.state.users.map((user)=>{ return <User name={user.name} age={user.age} interests={user.interests} key={user.id} /> }) return ( <div> {users} </div> ); } } export default UsersClass; |
The class component UsersClass will look like the one demonstrated above and will utilize a presentation component called User to display individual user details in a card.
Also, if the user searches for a specific name, the API call will have to be initiated again for the specific user name in the componentDidUpdate() function.
All of the above logic will be specific to our UsersClass component and we cannot reuse any of it, if we have a similar situation (making an API call and/or updating state) in another component.
This is the biggest differentiator that hooks provide in Functional components.
The standard useState and useEffect hooks enable the incorporation of state and life cycle event hooks in Functional components.
The useState hook
The useState hook lets us add the React state to functional components. This function hook takes the initial value of state as an argument and returns a two-element array containing the state value, and a function to update that value.
1 |
const [users, setUsers] = useState([]); |
useState takes the initial value as the input and returns the current state and the function to update the state(like the setState in the class components).
Now, we can get the current state using the first value returned (users) and use the second value returned (setUsers) if we need to update the state.
All of this can be achieved without the keyword ‘this’ being attached to it, as this pertains to a function and not a class.
The useEffect Hook
In the class components, we put any side-effects like API requests, manual DOM mutations, and logging into the lifecycle methods componentDidMount and componentDidUpdate. The useEffect hook handles the effects in the same way for functional components as well. This hook contains the logic to be executed after render.
The useEffect takes one mandatory parameter which is, the function that gets executed after render. By default, it gets executed every time render gets executed.
This can be optimized by making use of the second optional parameter.
If passed as an [](empty array), it gets executed only once, and if passed as some value [users], it gets executed only when the value, being passed as the second parameter changes.
For the user fetch example, only to get the user data in useEffect as below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
const Users = props =>{ const [users, setUsers] = useState([]); useEffect(() => { console.log("useEffect called"); axios.get('https://hooks-demo-a6d15.firebaseio.com/users.json') .then(res => { const users=[] for (const key in res.data){ users.push({ id: key, name :res.data[key].name, age: res.data[key].age, interests: res.data[key].interests}); } setUsers( users ); }) .catch(err => { console.log(err); }); },[]); |
This is the optimal approach if we want to fetch the data again while the search criteria or the dependent data changes.
How can Hooks be reused?
The hook-related logic can be separated into a custom hook(name prefix use for e.g. useUsers.js). It can be imported and invoked like a function in any other functional components that need to use the same logic.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
import { useState, useEffect } from 'react'; import axios from 'axios'; const useUsers = props =>{ const [users, setUsers] = useState([]); useEffect(() => { console.log("useEffect called"); axios.get('https://hooks-demo-a6d15.firebaseio.com/users.json') .then(res => { console.log('User fn info',res.data); const users=[] for (const key in res.data){ users.push({ id: key, name :res.data[key].name, age: res.data[key].age, interests: res.data[key].interests}); } setUsers( users ); }) .catch(err => { console.log(err); }); },[]); return users; }; export default useUsers; |
Now, it can be imported and used in a simple way as demonstrated below in any of the functional components.
1 2 |
import useUsers from './useUsers'; const users = useUsers(); |
This could prevent code duplication and make our functional components lighter and easier to understand.
You can find the complete code here
For the right technical advice from our experts, contact WalkingTree Technologies Today.
Avoiding Repetitive Computations and Re-rendering of DOM
Many times, we have complex computation logic which we would need to perform multiple times in our application even though the input is the same. The useMemo hook enables us to memoize any complex logic and ensure that it gets executed only when the input changes.
1 |
const memoizedValue = useMemo(() => computeComplexlogic(input1, input2, input3...inputn), [input1, input2,input3….inputn]); |
The computeComplexlogic function gets re-evaluated only when any one of the input values change. The value is memoized in the cache and used whenever referred to. The value will be recomputed if any of the listed inputs change
In the above example, the logic to render the User List can be memoized as below. Now, this will be re-rendered only if the users array value changes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
return (<div> Users {useMemo( () => ( users.map((user)=>{ return <User name={user.name} age={user.age} interests={user.interests} key={user.id} /> }) ), [users] )} </div>); |
This can be used for values/lists which do not change frequently.
CONCLUSION
In this blog, we saw some of the important hooks and how they can be used to improve the reusability of React code while reducing its complexity. Hooks are the future of React components that are moving towards functional programming where the functional components can be both simple presentation components, as well as, complex containers that maintain and manipulate the state.
You may also be interested in other blogs on REACT from our Experts at WalkingTree Technologies.
Very nice and detailed explanation of React hooks. Thank you.
React Hook , nicely explained