skip to Main Content

I am having a problem with useState hook in React it is causing to many re renders and the app breaks. I am trying using useState set function inside a return that has a lot of renders.

I have found out i can use useMemo or useCallback hooks to meonize the function. The the problem i am having pass aa parameter to this function.

somewhere in my code i am looking over a array and I want to and i want to call this function for every array item from the loop to process the data.

const myComponent = () => {
    
   const [example, setExample] = useState({});

   const myFunction = (item) => {
      setExample(item)
   }

    return (
        array.map(item => {
          const test = myFunction(item);
        
          <p>{test}</P
        })
    )
 }

SO the above is just example but how do i meonize myFunction since it takes a parameter i have tried:

const test = useMemo(item => setExample(item), [setExample]);

but when i then call test(item) in my map it does not work

2

Answers


  1. Here’s how you write a useCallback memoized function that accepts a parameter;

    const myFunction = useCallback((item) => {
     // Your logic here
    }, []); // Your useCallback deps here
    

    And here’s how you call it;

    myFunction(someItem)
    

    Also, note that you should only use useMemo when you want to memoize the returned results e.g array, object etc. You should use useCallback when you want to memoize a function itself.

    Login or Signup to reply.
  2. First, let’s talk about what useCallback is: it’s a syntactic sugar for wrapping a function in use useMemo.

    A normal usage of useMemo looks like this:

    useMemo(() => n*n, [n]) // notice that it takes a function.
    

    Then if you want to wrap a function, it becomes

    useMemo(() => arg => { ... }, []) // notice that it takes a function.
    

    useCallback simply shortens that to

    useCallback(arg => { ... }, []) // notice that it takes a function.
    

    With that out of the way, the issue you’re facing is that you are declaring myFunction in the body of the function. It’s identity changes on every render (it is redeclared every time).

    A memorization like this:

    function MyComponent() {
       const myFunc = (arg) => { }
       useCallback(myFunc, [myFunc])
    }
    

    will never work: myFunc changes every time, and the cached callback is not used.

    To make it work, you need to extract myFunc out:

    const myFunc = () => { }
    function MyComponent() {
       useCallback(myFunc, [myFunc])
    }
    

    Now myFunc has a stable identity and can be memorized between renders.

    Accordingly, your code should look like this:

    const myFunction = (item, setExample) => { // Notice, we need to extract `setExample` into its own argument
       setExample(item)
    }
    
    const myComponent = () => {
        
       const [example, setExample] = useState({});
    
       const myMemoizedFunction = useCallback(myFunction, []) // `myFunction` never changes, it's a global constant
    
        return (
            array.map(item => {
              // This causes a rendering loop. Remove this!
              // const test = myMemoizedFunction(item, setExample);
            
              <p>{test}</P
            })
        )
     }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search