Home > front end >  How to use useCallback hook with onChange function REACT
How to use useCallback hook with onChange function REACT

Time:05-22

I have simple React component: How I can improve this component by adding useCallback hook? Is it even a good idea to add useCallback hook in this component? If yes, to which function should I add it.

import styled from "styled-components"
import React, { useState } from "react"
import { useGetFilteredBooks } from "../../hooks/useGetFilteredBooks"
import { useRecoilState } from "recoil"
import { Books, PageNumber, SearchText } from "../../recoil/globalState"



export const SearchBook = () => {
    const [text, setText] = useRecoilState(SearchText)
    const [pageNumber, setPageNumber] = useRecoilState(PageNumber)
    const [setBooks] = useRecoilState(Books);
    const { refetch } = useGetFilteredBooks(text, setBooks, setPageNumber);

    const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>) => {
        setText(event.target.value)
    }

    const handleOnSubmit = (e: any) => {
        e.preventDefault();
        refetch();
    }


    return (
        <>
            <form onSubmit={handleOnSubmit}>
                <Input value={text} onChange={handleOnChange} placeholder="Enter the name of the book or author" />
                <button type="submit">Show</button>
            </form>
        </>
    )
}

const Input = styled.input`
    padding: 10px 10px;
    width: 300px;
`

CodePudding user response:

It is a good idea to memoize a function in useCallback if you know that you will be going to use those functions as a dependency in other hooks like useEffect or useMemo, in your case, your functions are pretty trivial and you are not using them as deps to other hooks, the computation cost of recreating them on each re-render is negligible hence the usage of useCallback, specifically, here is not needed. Just be aware that if you put other non memoized functions in the deps array of a useCallback, that will be worth nothing. If you still plan to wrap those functions in useCallback to use them in other components / hooks:

import styled from "styled-components"
import React, { useState, useCallback } from "react"
import { useGetFilteredBooks } from "../../hooks/useGetFilteredBooks"
import { useRecoilState } from "recoil"
import { Books, PageNumber, SearchText } from "../../recoil/globalState"



export const SearchBook = () => {
    const [text, setText] = useRecoilState(SearchText)
    const [pageNumber, setPageNumber] = useRecoilState(PageNumber)
    const [setBooks] = useRecoilState(Books);
    const { refetch } = useGetFilteredBooks(text, setBooks, setPageNumber);

    const handleOnChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
        setText(event.target.value)
    },[])  // No deps needed here according to ESLint, since react setState<s> do not change during re-renders.

    const handleOnSubmit = useCallback((e: any) => {
        e.preventDefault();
        refetch();
    },[refetch]) // refetch is needed here, since it might change during re-renders, you should make sure to memoize that function as well


    return (
        <>
            <form onSubmit={handleOnSubmit}>
                <Input value={text} onChange={handleOnChange} placeholder="Enter the name of the book or author" />
                <button type="submit">Show</button>
            </form>
        </>
    )
}

const Input = styled.input`
    padding: 10px 10px;
    width: 300px;
`

CodePudding user response:

What does useCallback do?

Per the docs:

useCallback will return a memoized version of the callback that only changes if one of the dependencies has changed.

So, memoized callbacks are essentially functions that survive rerender cycles.

Why would we need memoized callbacks?

Per the docs:

This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders (e.g. shouldComponentUpdate).

Combining memoized callbacks with components that rely on reference equality, useEffect is an example in functional components, avoids rerendering these child components unnecessarily.

Are you using components that rely on reference equality?

No. To make your application just "work", at the moment you don't need useCallback.

Should you still apply useCallback for performance?

One might think, useCallback might enable better performance since functions aren't recreated. This has been discussed in an article by Kent C. Doods or in this reddit. The bottom line is that premature, unscientific optimization is a waste of time, and potentially harmful. Refrain from applying memoization if you're application works and is fast enough.

CodePudding user response:

Is it even a good idea to add useCallback hook in this component?

No, it's not.

useCallback hook is used to preserve the referential integrity of a function object which is a fancy way of saying that it allows us to preserve a particular function object which in turn, helps us prevent unnecessary re-renders when that function is passed as a prop to the child component(s).

It is important to note that even with the useCallback hook, function is re-created on every render but it is discarded if the dependencies of the useCallback hook didn't change. So if your goal is to prevent the cost of re-creating the function on every render, useCallback won't help.

When should the useCallback hook be used?

This is best demonstrated using a demo.

In the following demo, counter is updated infinitely because of infinite execution of the useEffect hook in the CounterUpdater component.

function Counter() {
  const [counter, setCounter] = React.useState(0);
  
  const updateCounter = () => {
    setCounter(currentCounter => currentCounter   1);
  }

  return (
    <div>
      <h1>{counter}</h1>
      <CounterUpdater updateCounter={updateCounter}/>
      <h3>Infinite re-rendering            
  • Related