skip to Main Content

I am declaring useMemo onload of page for pagination. It is working fine. But when I tried to declare inside a response of service call I am getting this error "React Hook "useMemo" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function". Please find the code below just for reference.

Test.js

    import React, { useState, useEffect,useMemo,useRef } from 'react';

const Test = React.forwardRef((props, ref) => {
    const [currentPage, setCurrentPage] = useState(1);
    const [posts, setPosts] = useState([]);
    const currentTableData = useMemo(() => {    // working fine
        const firstPageIndex = (currentPage - 1) * PageSize;
        const lastPageIndex = firstPageIndex + PageSize;
        const getData = JSON.parse(sessionStorage.getItem("tableData"));
        //console.log(getData)
        return getData.slice(firstPageIndex, lastPageIndex);
      }, [currentPage]);

      const formikfilter = useFormik({
        initialValues: {
            month: '',
            year: '',
            amount: ''
        },
        //  validate: validatefData,
        onSubmit: values => {
            //  resetForm();
            var config = { "Access-Control-Allow-Origin": "*" }
            fetchData(values.year, config, (res) => {
                setPosts(res.data.items);
                const currentTableData = useMemo(() => { // getting errror
                    const firstPageIndex = (currentPage - 1) * PageSize;
                    const lastPageIndex = firstPageIndex + PageSize;
                    const getData = JSON.parse(sessionStorage.getItem("tableData"));
                    //console.log(getData)
                    return getData.slice(firstPageIndex, lastPageIndex);
                  }, [currentPage]);
                
            }, (err) => {
                //error
            
            });
        }
    });
})

3

Answers


  1. I believe the error message is clear – you are calling the useMemo hook inside a function, not inside a React component or a custom hook. If you really want to use this hook, you would have to move it out, to the component body, but it would require significant code structure changes to be able to access the values property, e.g. using the formik context.

    Anyways, the usage of useMemo here does not make much sense, because it is meant to avoid unnecessary, heavy recalculations between re-renders, but in your particular case, the recalculations will be done only on the onSubmit event, not between the re-renders. Any visible performance downsides will not occur.

    Login or Signup to reply.
  2. You’re encountering the error due to the fact that you’re attempting to use the useMemo hook inside a callback function (onSubmit callback of formikfilter). React hooks, including useMemo, are meant to be used directly within the functional component’s body or within custom hook functions, but not within nested functions or callbacks.

    useMemo cannot be called directly inside the onSubmit callback. Instead, you can calculate the currentTableData outside of the callback, preferably inside the main body of the functional component, using a regular variable or a separate function.

    You can try adjusting the code as below;

    import React, { useState, useMemo } from 'react';
    import { useFormik } from 'formik'; 
    
    const Test = React.forwardRef((props, ref) => {
      const [currentPage, setCurrentPage] = useState(1);
      const [posts, setPosts] = useState([]);
    
      const currentTableData = useMemo(() => {
        const firstPageIndex = (currentPage - 1) * PageSize;
        const lastPageIndex = firstPageIndex + PageSize;
        const getData = JSON.parse(sessionStorage.getItem("tableData"));
        return getData.slice(firstPageIndex, lastPageIndex);
      }, [currentPage]);
    
      const formikfilter = useFormik({
        initialValues: {
          month: '',
          year: '',
          amount: ''
        },
        // Other formik properties...
    
        onSubmit: values => {
          fetchData(values.year, config, (res) => {
            setPosts(res.data.items);
            // Do not use useMemo here
            // Instead, setPosts will trigger a re-render and currentTableData will 
     // be recalculated automatically.
          }, (err) => {
            // Handle error
          });
        }
      });
    
     return (
        <div>
          {/* Your component JSX */}
          {/* Use currentTableData and posts here */}
        </div>
      );
    });
    
    export default Test;
    

    With the suggested code the currentTableData variable is calculated once within the component’s main body using useMemo. Since it depends on currentPage, it will automatically update when currentPage changes.

    Additionally, you don’t need to manually recalculate currentTableData inside the onSubmit callback. React’s reactivity system will handle that for you when setPosts is called.

    Login or Signup to reply.
  3. React hooks cannot have local scope in a component, they need to included in global scope. You are declaring it a function hence it won’t be available outside the function and ultimately killing the purpose of using it. What you can do is declare the memo on global scope and store the data in a state, use currentPage state in your memo dependency then change the state in callback function as you did in your function. Also, I can’t seem to understand why would you want to call memo in your callback function, if its cause you want to trigger it when you can a response then you may wanna add Posts in your dependency array of memo.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search