HOOKS – Analysis about React Hooks

React hooks came into the picture in October 2018. In early February 2019, they finally came in React v16.8.0.React Hooks are a great addition to React which has completely changed how we write code.

Before React hooks, there was no way of using state and lifecycle methods in functional components, and that’s why the functional components were called Stateless functional components. After the introduction of reacting hooks, we can use lifecycle methods and states in functional components. Using Hooks makes our code simpler, shorter, and easy to understand for react developers.

Installation

We want to start using hooks. We must install the latest version of React and React dom.

Built-in Hooks

React provides many built-in hooks and also allows us to create our own custom hooks. Let’s look into some of the most important built-in hooks.

useState Hooks

This is the first hook provided by React to use State in functional components. useState returns an array with 2 elements, and we’re using ES6 destructuring to assign names to them. The first element is the current value of the state, and the second element is a state setter function – just call it with a new value, and the state will be set and the component will re-render.

Example :

import React, { useState } from 'react';

function Example() {

 // Declare a new state variable, which we'll call "count"

 const [count, setCount] = useState(0);

  return (

    <div><p>You clicked {count} times</p>

      <button onClick={() => setCount(count + 1)}>Increment counter</button>

    </div>

  );

}

useEffect Hooks

React provides a useEffect hook by which we can implement lifecycle methods in functional components. The useEffect hook accepts a function as its first parameter and an optional array as the second argument. useEffect lets you perform side effects in a functional component. It’s the solution to many problems: how to fetch data when a component mounts, how to run code when state changes or when a prop changes, how to set up timers or intervals, you name it.

If you have been working with React for several years, it is especially crucial to understand how working with useEffect differs from working with the lifecycle methods of class-based components. In fact, it is a wholesale shift in mindset!

Example :

import React, { useState, useEffect } from "react";

import ReactDOM from "react-dom";

function App() {

 const [count, setCount] = useState(0);

 useEffect(() => {

   console.log("second on update"); // It will print whenever click on button

   return () => {

     console.log("first on update"); // It will print whenever click on button

   };

 });

 return (

   <div>

     <p>You clicked {count} times</p>

     <button onClick={() => setCount(count + 1)}>Click me</button>

   </div>

 );

}

const rootElement = document.getElementById("root");

ReactDOM.render(<App />, rootElement);

useLayoutEffect Hooks

This runs synchronously immediately after React has performed all DOM mutations. This can be useful if you need to make DOM measurements (like getting the scroll position or other styles for an element) and then make DOM mutations or trigger a synchronous re-render by updating the state.

As far as scheduling, this works the same way as componentDidMount and componentDidUpdate. Your code runs immediately after the DOM has been updated, but before the browser has had a chance to “paint” those changes (the user doesn’t actually see the updates until after the browser has repainted).

One other situation you might want to use useLayoutEffect instead of useEffect is if you’re updating a value (like a ref) and you want to make sure it’s up-to-date before any other code runs.

Example :

const ref = React.useRef()

React.useEffect(() => {

 ref.current = 'some value'

})

// then, later in another hook or something

React.useLayoutEffect(() => {

 console.log(ref.current) // <-- this logs an old value because this runs first!

})

useRef Hooks

In a React component, useState and useReducer can cause your component to re-render each time there is a call to the update functions. Use the useRef() hook to keep track of variables without causing re-renders, and how to enforce the re-rendering of React Components.

If you used class components before the React 16.8 version, you know that this is how we would create a reference to a component or an element:

Example :

class Button extends React.Component {

constructor(props) {

  super(props);

  this.buttonRef = React.createRef();

}

render() {

  return (

    <button ref={this.buttonRef}>

      {this.props.children}

    </button>

  )

}

}

Import the createRef method from React, and pass it to the element that you want. Pretty simple.

The useRef hook holds the actual value in its current method. With this method, we can access the actual HTML element, in our case, a button. By using the current method, we can do some things and change HTML elements imperatively using some node instances, such as .focus, .contains, .cloneNode, etc.

But, now, we can do everything that we were doing with class components, with functional components! We can now manage our state logic inside a functional component, we can have “lifecycle methods” and we can create references and pass them to elements by using the useRef hook.

The useRef hook allows us to return a mutable ref object (a DOM node or element created in the render method).

Example :

import React, { useRef } from "react";

const Button = ({ children }) => {

 const buttonRef = useRef();

 return (

   <button ref={buttonRef}>{children}</button>

 )

}

But, what’s the difference between the createRef and the useRef? Well, pretty simple: the createRef hook creates a new reference every time it renders, and the useRef hook will return the same reference each time.

useCallback Hooks

useCallBack hooks take as an argument a function and return a cached/memoized version of it. It also takes a second parameter which will be covered later.

At a glance, it seems that this Hook is pretty straightforward. It accepts 2 arguments: a callback function and an array of dependencies. It returns a memoized callback function when any value in the dependency array has changed.

useCallback is used to optimize the rendering behavior of React functional components. It’s useful when a component is being constantly re-rendered and there’s complex function behavior inside of it. We’ll be taking a look at a simple example of how to implement this hook to see how it can help us gain efficiency in re-rendering components.

Example :

const App = () => {

  const [delta, setDelta] = useState(1);

  const [c, setC] = useState(0);

 

  // No dependencies (i.e. []) for now

  const incrementDelta = useCallback(() => setDelta(delta => delta + 1), []);

  const increment = useCallback(() => setC(c => c + delta), []);

 

  // Register the functions so we can count them

  functions.add(incrementDelta);

  functions.add(increment);

 

  return (<div>

    <div> Delta is {delta} </div>

    <div> Counter is {c} </div>

    <br/>

    <div>

      <Button onClick={incrementDelta}>Increment Delta</Button>

      <Button onClick={increment}>Increment Counter</Button>

    </div>

    <br/>

    <div> Newly Created Functions: {functions.size - 2} </div>

  </div>)

}

useMemo Hooks

React has a built-in hook called useMemo that allows you to memoize expensive functions so that you can avoid calling them on every render. You simply pass in a function and an array of inputs and useMemo will only recompute the memoized value when one of the inputs has changed. In our example below we have an expensive function called computeLetterCount (for demo purposes we make it slow by including a large and completely unnecessary loop). When the current selected word changes you’ll notice a delay as it has to recall computeLetterCount on the new word. We also have a separate counter that gets incremented every time the increment button is clicked. When that counter is incremented you’ll notice that there is zero lag between renders. This is because computeLetterCount is not called again. The input word hasn’t changed and thus the cached value is returned.

Example :

import React from "react";

import ReactDOM from "react-dom";

const App = () => {

  const urls = React.useMemo(

    () => [  "https://jsonplaceholder.typicode.com/posts/1",

      "https://jsonplaceholder.typicode.com/posts/2",

      "https://jsonplaceholder.typicode.com/posts/3",

      "https://jsonplaceholder.typicode.com/posts/4"

    ],

    []

  );

  const [results] = useUrls(urls);

  console.log(results);

return <div />;

};

const rootElement = document.getElementById("root");

ReactDOM.render(<App />, rootElement);

Leave a Reply