How to dispatch a thunk from a saga?

与世无争的帅哥 提交于 2019-12-23 14:02:24

问题


I know I shouldn't be trying to dispatch thunks from sagas, it goes against what redux-saga tries to do. But I'm working in a fairly large app and most of the code is made with thunks, we are migrating by bits and need to dispatch a thunk from inside a saga. The thunk can't be changed because it is used in other parts (a thunk that returns a promise), so it would break many things.

configureStore:

const store = createStore(
  rootReducer,
  initialState,
  compose(applyMiddleware(thunk, sagaMiddleware))
);

Saga:

// Saga (is called from a takeEvery)
function* watchWarehouseChange(action) {
  const companyId = yield select(Auth.id);

  // We use cookies here instead of localStorage so that we persist
  // it even when the user logs out. (localStorage clears on logout)
  yield call(Cookies.set, `warehouse${companyId}`, action.warehouse);

  // I want to dispatch a thunk here
  yield put.resolve(syncItems);
  // put(syncItems) doesn't work either
}

Thunk:

export function syncItems() {
  console.log('first!');

  return dispatch => {
    console.log('second!');

    return dispatch(fetchFromBackend()).then(
      items => itemsDB.emptyAndFill(items)
    )
  }
}

Whenever syncItems() is executed, only first! logs. second! never happens.

PS: I don't get any errors or warnings.


回答1:


You're using syncItems wrong. The key is that the function returned by syncItems needs to get passed to dispatch, not syncItems itself. The correct usage would be:

yield put(syncItems());

I showed some visual comparisons of how values are passed into dispatch in my blog post Idiomatic Redux: Why use action creators? (based on an example gist I put together). Here's the examples:

// approach 1: define action object in the component
this.props.dispatch({
    type : "EDIT_ITEM_ATTRIBUTES", 
    payload : {
        item : {itemID, itemType},
        newAttributes : newValue,
    }
});

// approach 2: use an action creator function
const actionObject = editItemAttributes(itemID, itemType, newAttributes);
this.props.dispatch(actionObject);

// approach 3: directly pass result of action creator to dispatch
this.props.dispatch(editItemAttributes(itemID, itemType, newAttributes));

// parallel approach 1: dispatching a thunk action creator
const innerThunkFunction1 = (dispatch, getState) => {
    // do useful stuff with dispatch and getState        
};
this.props.dispatch(innerThunkFunction1);

// parallel approach 2: use a thunk action creator to define the function        
const innerThunkFunction = someThunkActionCreator(a, b, c);
this.props.dispatch(innerThunkFunction);

// parallel approach 3: dispatch thunk directly without temp variable        
this.props.dispatch(someThunkActionCreator(a, b, c));

In your case, just substitute yield put for this.props.dispatch, since you're dispatching from a saga instead of a connected component.




回答2:


use https://github.com/czewail/bind-promise-to-dispatch package

add resolve and reject paramers in saga func

then use this package func wrap this.props.dispatch

then you can use it with promise



来源:https://stackoverflow.com/questions/44334008/how-to-dispatch-a-thunk-from-a-saga

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!