Reputation: 804
I have three slices ProductSlice
, CategorySlice
and BrandSlice
. Each slice has createAsyncThunk
which makes fetch request for products, categories and brands.
CategorySlice
(BrandSlice
the same):
export const fetchCategories = createAsyncThunk('category/fetchCategories', async () => {
const response = await fetch(`${BASE_URL}/categories.json`);
const data = await response.json();
const categories: Category[] = handleObj(data);
return categories;
});
builder.addCase(fetchCategories.fulfilled, (state, { payload }) => {
state.categories = payload;
state.isLoading = false;
});
App component dispatches three fetch requests.
useEffect(() => {
dispatch(fetchCategories());
dispatch(fetchProducts());
dispatch(fetchBrands());
}, [dispatch]);
I need to get data from brands and categories. Then get data for products and add some data to each product and only after that set it to ProducSlice
state. The data should come from categories and brands. I'm trying to it in ProductSlice
createAsyncThunk
this way:
export const fetchProducts = createAsyncThunk<Product[], void, { state: RootState }>(
'product/fetchProducts',
async (_, { getState }) => {
const response = await fetch(`${BASE_URL}/products.json`);
const data = await response.json();
const products: Product[] = handleObj(data);
const { brands } = await getState().brand;
const { categories } = await getState().category;
const productsWithUpdatedBrandsAndCategories = products.map((product) => {
const category = categories.find((category) => category.id === product.category.id);
const brand = brands.find((brand) => brand.id === product.brand.id);
if (!category && !brand) return product;
return {
...product,
category: {
...category,
name: category && category.name,
},
brand: {
...brand,
name: brand && brand.name,
},
};
}) as Product[];
return productsWithUpdatedBrandsAndCategories;
}
);
The problem is that from time to time the brands or categories in ProductSlice in thunk are empty arrays (I mean the thunk fires when the data has not came from other slices..so productsWithUpdatedBrandsAndCategories
do nothing then). How to deal with that?
Upvotes: 3
Views: 1072
Reputation: 202836
It seems there is a dependency on fetchCategories
and fetchBrands
and subsequent state updates prior to being able to dispatch fetchProducts
to have the brand and categories state available.
I suggest a little refactor to dispatch the first two actions and wait for them to resolve then dispatching the third.
Example:
useEffect(() => {
const fetchData = async () => {
try {
// fetch brands and categories and wait for actions to resolve
await Promise.all([
dispatch(fetchBrands()),
dispatch(fetchCategories()),
]);
// now fetch products
dispatch(fetchProducts());
} catch(error) {
// handle or ignore errors?
}
};
fetchData();
}, [dispatch]);
...
export const fetchProducts = createAsyncThunk<Product[], void, { state: RootState }>(
'product/fetchProducts',
async (_, { getState }) => {
const response = await fetch(`${BASE_URL}/products.json`);
const data = await response.json();
const products: Product[] = handleObj(data);
const {
brand: { brands },
category: { categories },
} = getState();
const productsWithUpdatedBrandsAndCategories = products.map((product) => {
const category = categories.find((category) => category.id === product.category.id);
const brand = brands.find((brand) => brand.id === product.brand.id);
if (!category && !brand) return product;
return {
...product,
category: {
...category,
name: category && category.name,
},
brand: {
...brand,
name: brand && brand.name,
},
};
}) as Product[];
return productsWithUpdatedBrandsAndCategories;
}
);
Upvotes: 2