React Hooks- Understanding the basics

Srijan Rana
MakeMyTrip-Engineering
6 min readMar 30, 2019

--

React Conf, 2018 witnessed a significant introduction in the world of React and that is ‘Hooks’ (available from v16.8.0) which now allows us to use features of Stateful Components in Functional Components. Hooks are basically functions that let us include react state and lifecycle features without using Classes, and organise the logic inside a component into reusable, isolated units.

We continuously strive to upgrade our technology. Recently in MakeMyTrip we revamped our pages, bringing them on latest Technologies. We developed our pages on React to deliver a better user experience, improved overall performance and reduced infra cost.

During our journey of revamping our website, using React and OOJs, we were developing an app with better load time and improved user interface, but how did our javascript bundle look like? Babel was transpiling our code to browser compatible JS. In this transpiled code, react components developed using Classes were converted into bigger chunks, but functional components were still smaller in size.

This raised a concern. Is OOJs really solving our problem of creating a fast & smaller sized app? Why not functional programming if it is creating smaller code chunks? How can we reduce our bundle size? This was the time when we stumbled upon newly launched React Hooks, which was providing a way of creating Functional stateful components, along with a smaller bundle size. Also, using Hooks was making our business logic more manageable and reusable.

Motivation for using Hooks:

We saw the rise and fall of Functional Programming, but in the past few years, we are witnessing a steep rise in Functional Programming over OOP. This changing trend brought our focus on functional programming making our code:

  1. Easier to read and test
  2. Less code
  3. Performance boost for functional component

In our project there was a lot of business logic that required using ‘State’ which was not possible to use in Functional Component, so initially we had to use Class based components to achieve the same until Hooks came into existence.

As we know that Classes were introduced in ES 2015 which is still not understood by many browsers so we use Babel to convert ECMAScript 2015+ code into a backwards compatible version of JavaScript. I did a POC as to how using Hooks would be beneficial in our project to achieve the same objective as Stateful components and here is a simplified version of the POC done.

Class based Component to Backward compatible JS Code
Functional Component to Backward compatible JS Code

It is clearly evident that the size of converted Class Based Component is significantly more than a functional component due to which the Webpack chunk size also increases which can affect the performance, so to reduce the overall size of chunks we started using Hooks to create our components.

Here is a small component that I built using both ways and got a size difference of 4.4 KB (about 9.6 –12.08 % less) on my dev machine and considering there are many components in our project with several lifecycle method this value becomes noticeable, therefore we started using Hooks to create our components for lesser code and better design pattern

Comparison of chunk size on my local machine (Class Based vs Functional Component using hooks)

Hooks: Making our lives simpler:

  1. Introduction to hooks have allowed reusing of stateful logic between components: This can be achieved by writing our own custom hooks that can be used inside any components. For eg. creating a custom hook for API calls.
  2. Writing complex components will become easier: Many a times a lot of business logics are written in our life cycle method making it difficult to understand and debug. Hooks instead allows us to separate these logics into smaller, isolated functions.

Using States in Functional Component: State Hook

In order to use states in Functional Component, React has now introduced useState.

Let’s see how to use this hook:
const [count, setCount] = useState(10);

Here useState declares a state variable which is named count (name can be anything), useState accepts none or one argument which is the initial state value, here I am passing a default value as 10, unlike Class component we don’t need to set value of state in form of an object, it can be of any data type like string, number and so on.

useState returns an array which includes the current state and a function that updates it. In the above syntax setCount is the function returned that allows us to update the value of the state count. Example: setCount(20), value of count is updated from 10 to 20.

Implementing same logic in Class Component and Functional Component using hooks

Performing Side Effects in Functional Component: Effect Hook

React v16.8.0 brings a new hook called useEffect that lets us implement life cycle methods which were native to Class based components. By using this hook we tell React that the component needs to do something after render. React will remember the function we passed, and call it later after performing the DOM updates.

By default, it runs after every render, and the behaviour of this can be controlled to implement lifecycle methods.

In this article I will show how to implement:

  1. componentDidMount()
  2. componentDidUpdate()
  3. componentWillUnmount()
useEffect(() => {
// perform a task
});

Implementing componentDidMount() using Hooks:

We know that useEffect runs after every render, but the behaviour of componentDidMount() is to execute a logic only after first render. Along with a function as a parameter useEffect also accepts second argument which should be an array that tells useEffect to execute the passed function only when the second argument changes.

So, to implement componentDidMount() we can pass an empty array []. By doing this, the function passed in useEffect will always run for the first time but for subsequent re-renders it would not re-run as the value of the array would not change.

useEffect(() => {
// perform a task
}, []);

Implementing componentDidUpdate() using Hooks:

This method is invoked immediately after the component is re-rendered, and according to typical usage, the logic should be wrapped inside a condition to avoid an infinite loop.

componentDidUpdate(prevProps) {
if (this.props.value !== prevProps.value) {
this.fetchData(this.props.value);
}
}

So to implement componentDidUpdate() we can just add the dependency in the array which is passed as second argument in useEffect. Now the logic would be executed only when that particular value changes.

useEffect(() => {
fetchData(props.value);
}, [props.value]);

Implementing componentWillUnmount() using Hooks:

Till now we have seen that the function in useEffect does not return anything, useEffect can either return nothing or return a function which is executed:

  1. Before useEffect runs the next time
  2. When the component unmounts (the logic inside the function passed in the hook would not be executed)
useEffect(() => {
console.log('Logic...')
return () => {
console.log('Cleaning up...')
}
}, [props.value]);
Output for the above snippet

Here is a comparison of life cycle hooks implemented in Class Component and Functional Component:

Rules for using hooks:

  • Call Hooks only at the top level. Don’t try to call Hooks inside loops, conditions, or nested functions.
  • Call Hooks only from React function components. Don’t try to call Hooks from regular JavaScript functions.

Conclusion

Using hooks helped us in improving our design pattern of our code and performance of our app, and we encourage you to use it in your projects too. Class Components are not getting obsolete so one doesn’t need to rewrite Class Based Components using Hooks. Please reach out to me for any queries regarding this. Thanks !

Hope you find this article useful. Happy Learning !

--

--