0

I have an auto-suggest component, which displays search results. On clicking a result, I am triggering an action SEARCH_RESULT_CLICKED which in turn invokes two sagas.

Saga 1, takes the text of the result, and triggers an action ITEM_SUMMARY_FETCHED with payload as

{ text: ... }

which displays it in a component, say B that implements a reducer for ITEM_SUMMARY_FETCHED.

Saga 2, takes the id of the result, and makes an API call. Once the result is fetched, it triggers ITEM_SUMMARY_FETCHED with payload as

{ description : ... }

The component B is expected to display, the text and description. of the selected result, the reducer is somewhat like this :

case 'ITEM_SUMMARY_FETCHED':
  return {
    ...state.itemdetails,
    ...action.summary,
  };

I was hoping that the properties will get merged, but it does not do so. When Saga 2 triggers the action, state is undefined. Consequently, the value of text gets removed and only the description is shown.

Can anyone help me with where I might be going wrong ?

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
jagzviruz
  • 1,453
  • 12
  • 27

1 Answers1

0

Would it be possible in your scenario to call one saga from within the other and compose a single object that you want to dispatch to the store. Here's a workflow I imagine:

  1. On SEARCH_RESULT_CLICKED invoke only your first saga.
  2. Within that saga, invoke your second saga. Your generator should pause and wait for the API to finish fetching the requested data.
  3. Compose a single object (back within your first saga) that contains the text and description field, the text coming from the action and the description coming from the API request made (and returned from) your second saga.
  4. Dispatch a single action from your first saga with this recomposed object. This will update the store only once.

This is a pattern I use often - invoking one saga from another. It isn't great for saga reusability since it assumes these sagas will always be run together. But if that's the scenario you're looking for, this may work.

You may also look into using yield all to run tasks in parallel: https://redux-saga.js.org/docs/advanced/RunningTasksInParallel.html.

Edit

Per your comment about having two different events, you may take a look at this question concerning fork. Using fork will start a non-blocking task in your saga, so you won't need to wait for the API to return. You would simply:

  1. yield fork(CALL_TO_API) - this will start the API call but not block.
  2. yield put(ACTION_TO_UPDATE_TEXT) - this will update Redux with the text.
  3. yield take(REFERENCE_TO_API_CALL) - this will now wait until CALL_API returns.
  4. yield put(ACTION_TO_UPDATE_DESCRIPTION_WITH_API_RESPONSE) - this will update Redux with the description returned data from your API.

It's not great to update UI in pieces like this - typically best to wait for all data to arrive before updating UI. You may want to do some API optimization to figure out why it takes 3 - 5 seconds to resolve. Good luck!

Parker Ziegler
  • 980
  • 6
  • 13