6

I have context in my react-app, I want to call a query in context and set the state value to an object from the api data. I have tried the following and I get the error, can't read property of undefined (4). So I know this could be because the data has not yet been returned and therefore I can't set the state to the object in the array, so how to get around this? Also how would I handle the status i.e loading etc in the component the context is passed to.

Another question is should I be calling the API in context, or should I call in the component and then set the context state in the component? is that better approach?

Code so far:

export const DataProvider: React.FunctionComponent = ({ children }) => {
 const getApi = async (): Promise<any> => {
    const response = await axios.get(`https://www.xxxxxx`).then(res => res.data);
    return response;
  }

  const { data: result, status, error, isFetching }: any = useQuery(['apiData'], () => getApi());

  const [myValue, setmyValue] = React.useState(result[4]); // this is causing the issue

  return (
    <DataContext.Provider value={{myValue, setmyValue, result}}>
      {children}
    </DataContext.Provider>
  );
};

1 Answer 1

10

react-query will give you undefined for data as long as isLoading is true. Since the initial value of useState is synchronous, this cannot really work.

if you really want to copy state from react-query, what you have to do is call the setMyValue in onSuccess or in a useEffect:

const { data, status, error, isFetching } = useQuery(['apiData'], () => getApi());

React.useEffect(() => {
  if (data) {
    setMyValue(data)
  }
}, [data])

This would also make sure that background updates would be properly reflected in your state. However, you usually don't need to do this at all:

I want to call a query in context and set the state value to an object from the api data.

I'm guessing that you think you want this because you want to have the data accessible anywhere in the app. The good news is that react-query is a state manager, and you can just do something like:

export const useApiData = useQuery(['apiData'], () => getApi());

and then you can call const { data } = useApiData() wherever you want in your app to retrieve the cached data. You will also get background updates for free.

I've written extensively about this topic in: React Query as a State Manager

Sign up to request clarification or add additional context in comments.

2 Comments

When would it be a good idea to use the useEffect?.
is this a good example? server gives whether a form is notstarted or done, in UI we need to show a Progress indicator if it is being edited in Ui. So we store the fetched state (using setState or reducer) and when it is being edited set the same state to inProgress state. 1. query => { status: notStarted } set the query state to local state using set state 2. status = notStarted make some edits to the form 3. change the status to inProgress.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.