d
WE ARE EXPERTS IN TECHNOLOGY

Let’s Work Together

n

StatusNeo

React Hooks

A complete guide to React Hooks for optimization

What are React Hooks?

Hooks are introduced in the React 16.8 version. React Hooks are special functions that can only be used in functional components and we can also use hooks in custom hooks. By using the hook functions in functional components we can use state and lifecycle methods inside functional components.

There are some Important Rules for Hooks

Before practicing with Hook, let’s discuss some rules of using hooks.

  • Hooks cannot be used inside any function, loop, or condition.
  • We can call Hooks from another Hooks.
  • Hooks can only be called from React functional components.
  • Hooks should be used at the top level of our component.

Let’s discuss and hand dirty on React Hooks

  • useState
  • useEffect
  • useContext
  • useReducer
  • useCallback
  • useMemo
  • useRef

useState()

So, useState is basically used to manage our functional component’s local state. It accepts the initial value and returns a current state and a function that updates the state. Our React state will not be updated by useState immediately as React useState and setState don’t make changes directly to the state object; they create queues to optimize performance, which is why the changes don’t update immediately.

First, we will import useState from react.

const[value, setValue] = useState(0)

const increment = () =>{
   setValue(value+1)
}

useEffect()

useEffect is basically used to perform side effects in our components. We can use class component life cycle methods in our functional component by using useEffect hook. It takes two arguments first is a callback function and the second one is dependency and the second argument is optional.

Let’s take an example

useEffect(() => {
// It will run only at the time of first render
},[])

useEffect(() => {
// When there is no dependency it will run on every render
})

useEffect(() => {
// First it will run at the time of first render
// And then it will run when dependency value changes.
},[value])

useContext()

useContext is basically used to create global or common that can be accessed by other components of our application it helps us to overcome props drilling. As compared to redux it is best for small applications and it is easy to understand and requires less code. We can manage our global data by creating context.

Let’s understand how to create context

context.js

import { createContext } from "react";
const UserContext = createContext({});
export const UserProvider = UserContext.Provider;
export default UserContext;


App.js

import React, { createContext, useState, useEffect } from "react";
import UserList from "./userContext";
import { UserProvider } from "./context";

function App() {
  const [user, setUser] = useState([]);

  const fetchData = async () => {
    try {
      const res = await fetch("https://jsonplaceholder.typicode.com/users");
      const json = await res.json();
      setUser(json);
    } catch (error) {
      console.log("error", error);
    }
  };
  useEffect(() => {
    fetchData();
  }, []);

  return (
    <UserProvider value={user}>
      <UserList />
    </UserProvider>
  );
}

export default App;

userList.js

import UserContext from "./context";
import React, { useContext } from "react";

function UserList() {
  const user = useContext(UserContext);

  return (
    <div>
      {user.map((item, index) => (
        <p>{item.username}</p>
      ))}
    </div>
  );
}

export default UserList;

Basically, we are creating a context in context.js and in app.js we use the Provider to make a value available to all children components after that we are using that context in our userList.js by useContext.

useReducer()

We can use useReducer as an alternative to the useState hook for managing the complex state logic in React applications. In useReducer, we store and update our state as we do in the useState. useReducer accepts two parameters first one is the reducer function and the second one is the initial state.

import React,{useReducer} from "react";

const reducerFunction = (state, action) => {
  if (action.type === 'increment') {
    return { count: state.count + action.payload };
  }
  if (action.type === 'decrement') {
    return { count: state.count - action.payload };
  }
};

export default function App() {
  const [state, dispatch] = useReducer(reducerFunction, {count :0});

  return (
    <div className="App">
      <p>Count{state.count}</p>
      <button onClick={() => dispatch({type: 'increment', payload: 1})}>Increment</button>
      <button onClick={() => dispatch({type: 'decrement', payload: 1})}>Decrement</button>
    </div>
  );
}

Basically in this, we are creating a state using useReducer Hook. and in that, we pass the reducer function and an object with the initial value. In the reducer function, we are getting the action type and payload when clicking on the button after that we are checking the action that needs to be performed.

useCallback()

The useCallback Hook will return a returns a memoized callback function that only changes if one of the dependencies has changed. The useCallback Hook is used when we have a component in which the child is rerendering again and again without need when we are doing changes in our parent component. We can pass an inline callback and an array of dependencies.

app.js

export default function App() {
  const [count, setCount] = useState(0);
  const [childCount, setChildCount] = useState(0);

  const increment= () => {
    setCount(count + 1)
  }

  const childIncrement= useCallback(() => {
    setChildCount(childCount + 1)
  },[childCount]);


  return (
    <div className="App">
      <p>Count{count}</p>
      <button onClick={increment}>Increment</button>
      <Child childCount={childCount} childIncrement={childIncrement}  />
    </div>
  );
}

child.js

import React,{memo} from 'react';

function Child({childCount,childIncrement}){
  return(
    <div>
      <p>ChilCount{childCount}</p>
        <button onClick={childIncrement}>childIncrement</button>
    </div>
  )

}

export  default memo(Child);

So, here if we will not use useCallback Hook to our childIncrement function then our child component will re-render when we increment the value of count even when our childCount is not changing. But now when we memorized our childIncrement function our Child component will not re-render until childCount will not change.

useMemo()

The useMemo Hook will return a memorized value. It will run only when one of its dependencies updates. It allows you to memoize expensive functions so that you can avoid calling them on every render.  A memoized function remembers the results of output for a given set of inputs.

import React,{useState,useMemo} from "react";
import Child from './child'

export default function App() {
  const [increment, setIncrement] = useState(0);
  const [decrement, setDecrement] = useState(0);

  const sum = () => {
    let sum = 0;
    for (let i = 0; i < 100; i++) {
      sum = sum+i;
    }
    console.log('sum', sum );
    return sum;
  };

  const expensiveFunction=useMemo(()=>sum(),[increment])

  return (
    <div className="App">
      <div>
        <button onClick={() => setIncrement(increment + 1)}>Increment</button>
        <button onClick={() => setDecrement(decrement - 1)}>Increment</button>
        <span>{increment}</span>
        <span>{decrement}</span>
      </div>
      <div>{expensiveFunction}</div>
    </div>
  );
};

Let’s discuss all cases:

First, if we will not use useMemo then our sum function will run every time we increment our count.

Second, if we will not pass any dependency then the sum will console only once.

const expensiveFunction=useMemo(()=>sum(),[])

Third, when we are giving dependency of increment sum will re-render when we update increment.

useRef()

The useRef Hook allows you to directly create a reference to the DOM element in the functional component and it stores a mutable value that does not cause a re-render when updated. The useRef Hook is a function that returns a mutable ref object whose .current property is initialized with the passed argument (initialValue).

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

export default function App() {
  const [text, setText] = useState('');

  const textInput = useRef();

  const focusTextInput = () => textInput.current.focus();

  const onChangeHandler = () =>{
    setText(textInput.current.value)
  }
 
  return (
    <>
      <input type="text" onChange={onChangeHandler} value={text} ref={textInput} />
      <button onClick={focusTextInput}>Focus the text input</button>
    </>
  );
}

Conclusion

In this blog, we have covered different React Hooks.

For more interesting blogs visit- StatusNeo Blogs

Thanks for reading, Ba-Bye for now.

I am always eager to learn new tech stacks to overcome my challenges in every field. I love playing games, bike riding, and recharging in nature.

Comments

  • April 6, 2023

    Can you be more specific about the content of your article? After reading it, I still have some doubts. Hope you can help me.

Add Comment