Uncaught (in promise) ReferenceError: xxx is not defined in react in useCallBack

Viewed 456

I have one Home component that need to wait for requestQuery api finish then parse the response data and pass the data into Child component as following code. if I move data variable out of useCallBack and hardcode the response data as mock data. my code is working. However after I move the data variable into useCallBack with async function I got the error Uncaught (in promise) ReferenceError: results is not defined How should I solve it?

import React, {useCallback, FC, useEffect, useState} from 'react';
export const Home: FC = () => {
  const initData = useCallback(async (): Promise<void> => {

      // attempt to load based on flow
  const [hasLoadingFailed, setLoadingFailed] = useState<boolean>(false);
  const [isLoading, setLoading] = useState<boolean>(false);

    try {
      const {data, errors} = await requestQuery({num: 1});

      // if errors or no data, throw error
      if (!data || errors?.length) throw Error('Errors Retrieving Data');

      const {results = []}: QueryResponse = data;
      console.log({results}); //no problem to get results
    } catch {
      setLoadingFailed(true);
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    initData();
  }, [initData]);

  return (
    <div><Child data={results} /></div>
  );
};
``
1 Answers

Issue

I'm sure you should be seeing a linting error about calling the useState React hooks in a callback, which breaks the Rules of Hooks. Additionally, results being passed to Child is undefined since it's only declared within the useCallback hook's callback scope, not the Home component function scope.

Solution

Fix the issues with the useState hooks and declare a results state to be passed to children components.

import React, { useCallback, FC, useEffect, useState } from 'react';

export const Home: FC = () => {
  const [hasLoadingFailed, setLoadingFailed] = useState<boolean>(false);
  const [isLoading, setLoading] = useState<boolean>(false);
  const [results, setResults] = useState<any[]>([]); // <-- default results state

  const initData = useCallback(async (): Promise<void> => {
    setLoading(true);
    try {
      const {data, errors} = await requestQuery({ num: 1 });

      // if errors or no data, throw error
      if (!data || errors?.length) throw Error('Errors Retrieving Data');

      const { results = [] }: QueryResponse = data;
      console.log({ results }); //no problem to get results

      setResults(results); // <-- update the results state
    } catch {
      setLoadingFailed(true);
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    initData();
  }, [initData]);

  return (
    <div>
      <Child data={results} />
    </div>
  );
};
Related