2

I am studying GraphQL/Apollow and React, now I want to fetch data using useQuery(or useLazyQuery). More specifically, I have two queries, query B is dependent on the result of query A, that is, I need to skip query B for some query A results, and not skip for other results. Moreover, I want to have loading spinner while fetching data.

My current solution: useEffect with [] parameters + useLazyQuery (Apollo) to only load data for one time, and at the same time updating loading state.

export const QUERY_A = gql `
  // something
`
export const QUERY_B = gql `
 // something
`

export default function ExampleModal(props: SomeType) {
  const [apiStatus, setApiStatus] = React.useState({
     loading: false,
     error: false
  });

  let resultA = '';
  const[getA] = useLazyQuery(QUERY_A, {
     onCompleted: (data) => { // won't  set loading to false, as we need to queryB
        resultA = data?.getAquery.status
     },
     onError: (error) => {
       setApiStatus({  
         loading: false,
         error: true
      });
     },
   });
   
   let resultB = '';
   
  const[getB] = useLazyQuery(QUERY_B, {
     onCompleted: (data) => {
        resultB = data?.getBquery.result;
        setApiStatus({   
         loading: false,
         error: false,
      });
     },
     onError: (error) => {
       setApiStatus({  
         loading: false,
         error: true
      });
     },
   },
   skip: resultA == 'something'   // this situation,we skip B
   );

  React.useEffect( () => {  
    setApiStatus({   // start loading
         loading: true,
         error: false
    });
 
    // fetch real data from A and B, 
    
    
  }, []); // use [] to just load for one time, when re-render, will not call apis again

  if (apiStatus.loading) return <div> loading...<div>
  if (apiStatatus.error) return <div> error...<div>
  return <div> real result <div>
} 

I know there may be a few issues here, my questions is:

  1. does the useEffect will stop immediately after state changes, saying when I
     setApiStatus({   // start loading
         loading: true,
         error: false
     });

will the component re-render immediately??

  1. How to store resultA and resultB, to not let them don't fetched again after re-render(I mean when loading stopped and I can get real result); should I do something like
    const [apiStatus, setApiStatus] = React.useState({
        loading: false,
        error: false,
        resultA: '',
        resultB: '',
     }); 

will this work?

  1. I just start, any suggestions for this kind of problems? any best pratices?

thank you so much!

2 Answers 2

1
  1. Your component will always rerender because you have used an object in the state. React doesn't do deep checks on the state. Either create a new object when doing setState using Object.assign() or separate loading and error.
const [loading, setLoading] = React.useState(false)
const [error, setError] = React.useState(false)

  1. I believe the invocation for GET B should happen inside the callback of GET A so you should only worry about how/when to call GET A.

You can use an empty useEffect and make API call to A conditionally if DATA A is undefined/null.

const [dataA, setDataA] = React.useState(null)
const [dataB, setDataB] = React.useState(null)

useEffect(() => {
 !dataA && apiCallForA
}, [])
Sign up to request clarification or add additional context in comments.

Comments

0

you can | loadings like

const [callFirst, {loading:loadingFirst}] = useLazyQuery(
    GET_QUERY,
    { variables: ... }
  );
const [callFirst, {loading:loadingSecond}] = useLazyQuery(
    GET_QUERY,
    { variables: ... }
  );

return ((loadingFirst | loadingSecond) && loading...)

return <Component/>

or you can call multiple query in one query

export const MULTIPLE_QUERY=gql`
query ($id:Int){
  post(id:$id){
    id 
    title
}
  comments(id:$id){
    id 
    title
}
}

`

Comments

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.