Bruno Monteiro
Bruno Monteiro

Reputation: 4519

How to fetch data from different APIs inside one redux-saga?

I have a React project using redux-saga and I need to call 2 APIs to fetch all the data I need.

If I need to fetch all my products, I usually do this:

function* fetchProducts() {
  const products = yield call(API.getProducts)
  yield put({type: "UPDATE_PRODUCTS", products})
}

Now imagine that my product object has a brandId field that I can use to fetch brand data from another API.

I wanted to:

  1. Fetch all the products
  2. Loop the products and, for each product, load its brand information
  3. Update my products object to include the brand information
  4. Save that new products object in my global state

I tried something like this:

function* fetchProducts() {
  const products = yield call(API.getProducts)
  const productsWithBrand = products.map((product) => {
    const brand = yield call(API.getBrand, product.brandId)
    return {
      ...product,
      brandData: brand,
    }
  })
  yield put({type: "UPDATE_PRODUCTS", productsWithBrand})
}

Which gives me the error:

Parsing error: Unexpected reserved word 'yield'

After reading this thread, I understood why the error is happening, but I can't figure out the proper syntax to achieve what I want.

Is there a common pattern to achieve what I need?

Upvotes: 2

Views: 685

Answers (1)

Lochana Ranaweera
Lochana Ranaweera

Reputation: 51

It is syntactically invalid to yield inside the function passed to map, since map has no idea about generators. A common pattern is to opt for a for...of loop or a regular for loop to perform an async operation for each item in the collection. https://medium.com/free-code-camp/redux-saga-common-patterns-48437892e11c

function* fetchProducts() {
    const products = yield call(API.getProducts);
    const productsWithBrands = [];
    for (let product of products) {
        const productWithBrand = yield call(API.getBrand, product.brandId);
    
        const { error } = yield race({
            success: take(SUCCESS),
            error: take(FAILURE),
        });
        
        if(error) {
            // Implement specific error handling
            // eg: break;
        }
        productsWithBrands.push(productWithBrand);          
    }
   yield put({type: "UPDATE_PRODUCTS", productsWithBrands });
}

Upvotes: 1

Related Questions