Call one query and wait for it to finish before calling another one

26 Views Asked by At

query PRODUCT_BY_ID needs to wait for query CATEGORIES to finish, after that I want to call query PRODUCT_BY_ID, I use data from the query CATEGORIES in the query PRODUCT_BY_ID, that is why I need to wait for query CATEGORIES to finish first, how can I do this?

If someone can help me I would really appreciate it.

useQuery<IProductCategoryQueryResult>(CATEGORIES, {
          variables: {
             pagination: { pageSize: 20 },
          },
          onCompleted: (res) => {
             if (!res) return;
    
             const { categories } = res;
             if (!categories) return;
    
             const { data } = categories;
    
             const allCategories: ICategories[] = data?.map((category: ICategoriesFinal) => ({
                id: category?.id,
                name: category?.attributes?.name,
                value: category?.attributes?.value,
             }));
    
             setCategories(allCategories);
          },
       });
    
       
       useQuery<IProductDetailQueryResult>(PRODUCT_BY_ID, {
          variables: {
             id,
          },
          onCompleted: (res) => {
             if (!res) return;
    
             const { product } = res;
             if (!product) return;
             const { attributes } = product.data;
    
             const imagesData = attributes?.images?.data;
             const imageUrls = imagesData?.map(
                (image: IProductDetailImage) =>
                   `${ENV.VITE_APP_AUTH_ENDPOINT}${image.attributes.url}`,
             );
    
             const imageIds = imagesData?.map((image: IProductDetailImage) =>
                parseInt(image.id),
             );
    
             const productDetail: IProductDetail = {
                reference: attributes?.reference,
                images: imageUrls,
                imagesId: imageIds,
                description: attributes?.description,
                numericPrice: attributes?.price?.numericPrice,
                displayPrice: attributes?.price?.displayPrice,
                category: attributes?.category?.data?.attributes?.value,
             };
    
             const checkCategory: ICategoryCheck = categories?.find(
                (category) => category.value === productDetail.category,
             );
    
             setImageUrlArray(imageUrls);
             setImageIdArray(imageIds);
    
             reset({
                reference: productDetail.reference,
                category: checkCategory.id,
                numericPrice: productDetail.numericPrice,
                displayPrice: productDetail.displayPrice,
                description: productDetail.description,
             });
    
             
          },
       });
1

There are 1 best solutions below

0
phry On

You probably generally shouldn't be any component-local state setters or the onCompleted callbacks here, as you might get multiple rerenders with inconsitent state in-between.

Instead, your first useQuery could be rewritten using derived state with useMemo like

const categoriesReturnValue = useQuery<IProductCategoryQueryResult>(CATEGORIES, {
  variables: {
     pagination: { pageSize: 20 },
  },
});
const categoies = useMemo(() => categoriesReturnValue.data?.map((category: ICategoriesFinal) => ({
  id: category?.id,
  name: category?.attributes?.name,
  value: category?.attributes?.value,
})), [categoriesReturnValue.data])

From that, getting to your real question: how to make the second query for the first?

For that, you'd use the skip option:

useQuery<IProductDetailQueryResult>(PRODUCT_BY_ID,
  {
    variables: {
      id,
    },
    // don't execute this query if we don't know `id` yet
    // you can use all kinds of logic here, this is just an example
    skip: id === undefined,
  });