I need your help. I am using react and redux along with typescript in my app. Using the code below, I get my products and their categories. The fact is that I get my products and they look great, but the categories don't work very well: sometimes i have to reload the page several times for them to appear, and sometimes i don't. Tell me how to fix it? Thank you very much
ApiService
export const getAllCategories = () => {
return async (dispatch: Dispatch<ProductActionModel>, getState: () => RootState) => {
try {
dispatch({ type: Action_types.GET_ALL_CATEGORIES });
const response = await fetch(`${environment.baseApiUrl}/products/categories`).then(res => res.json());
const state = getState();
dispatch({ type: Action_types.GET_ALL_CATEGORIES_SUCCESS, payload: [...state.products.categories, ...response] });
} catch (error) {
dispatch({ type: Action_types.GET_ALL_CATEGORIES_ERROR, payload: 'Something went wrong'})
}
}
}
export const getAllProducts = () => {
return async (dispatch: Dispatch<ProductActionModel>) => {
try {
dispatch({ type: Action_types.GET_ALL_PRODUCTS });
const response = await fetch(`${environment.baseApiUrl}/products`).then(response => response.json())
dispatch({ type: Action_types.GET_PRODUCTS_SUCCESS, payload: response.products })
} catch (e) {
dispatch({ type: Action_types.GET_PRODUCTS_ERROR, payload: 'Something went wrong' });
}
}
}
ProductReducer
const initialState: ProductsStateModel = {
products: [],
categories: [],
loading: false,
error: null
}
export const ProductReducer = (state = initialState, action: ProductActionModel): ProductsStateModel => {
switch (action.type) {
case Action_types.GET_ALL_PRODUCTS:
return { loading: true, error: null, products: [], categories: [] }
case Action_types.GET_PRODUCTS_ERROR:
return { loading: false, error: action.payload, products: [], categories: [] }
case Action_types.GET_PRODUCTS_SUCCESS:
return { loading: false, error: null, products: action.payload, categories: [] }
case Action_types.GET_ALL_CATEGORIES:
return state;
case Action_types.GET_ALL_CATEGORIES_ERROR:
return state;
case Action_types.GET_ALL_CATEGORIES_SUCCESS:
return { ...state, categories: [...state.categories, ...action.payload] }
default:
return state;
}
}
ProductList
const { products, error, loading, categories } = useTypesSelector(state => state.products);
const dispatch: ThunkDispatch<RootState, void, ProductActionModel> = useDispatch();
useEffect(() => {
dispatch(getAllProducts());
dispatch(getAllCategories())
},[dispatch])
console.log(categories); // sometimes fine, sometimes [], [], [categories], []
It seems you want to execute reducers in order. Can you do chaining like following?
const { products, error, loading, categories } = useTypesSelector(state => state.products);
const dispatch: ThunkDispatch<RootState, void, ProductActionModel> = useDispatch();
useEffect(() => {
dispatch(getAllProducts()).then(()=>dispatch(getAllCategories()));
},[dispatch])
console.log(categories); // sometimes fine, sometimes [], [], [categories], []
Or, make one reducer containing getAllProducts() and getAllCategories().
export const getAllCategories = () => {
return async (dispatch: Dispatch<ProductActionModel>, getState: () => RootState) => {
try {
dispatch({ type: Action_types.GET_ALL_CATEGORIES });
const response = await fetch(`${environment.baseApiUrl}/products/categories`).then(res => res.json());
const state = getState();
dispatch({ type: Action_types.GET_ALL_CATEGORIES_SUCCESS, payload: [...state.products.categories, ...response] });
} catch (error) {
dispatch({ type: Action_types.GET_ALL_CATEGORIES_ERROR, payload: 'Something went wrong'})
}
}}
export const getAllProducts = () => {
return async (dispatch: Dispatch<ProductActionModel>) => {
try {
dispatch({ type: Action_types.GET_ALL_PRODUCTS });
const response = await fetch(`${environment.baseApiUrl}/products`).then(response => response.json())
dispatch({ type: Action_types.GET_PRODUCTS_SUCCESS, payload: response.products })
} catch (e) {
dispatch({ type: Action_types.GET_PRODUCTS_ERROR, payload: 'Something went wrong' });
}
}}
export const initialLoader= () => {
return async (dispatch: Dispatch<ProductActionModel>, getState: () => RootState) => { // Unify above functions}}