createAsyncThunk:在同一个有效负载创建者中使用获取的数据更新存储后分派更多操作

createAsyncThunk: dispatch more actions after updating store with fetched data, within a same payload creator

我刚开始使用 Redux Toolkit(RTK),我很难找到使用 RTK 的 createAsyncThunk 的正确方法。

所以我想做的是

  1. 调度由 createAsyncThunk
  2. 创建的异步操作
  3. 用获取的数据更新存储,
  4. 并在同一个负载创建者中分派另一个同步操作。


例如,您可以使用 redux-saga 编写这样的代码,如下所示。

function* fetchBooksSaga() {
  try {
    yield put(fetchBooksStart()); // set loading
    const keyword = yield select(state => state.keyword); // get keyword from store
    const { data } = yield call(SearchBooksAPI, query); // fetch books
    yield put(fetchBooksSuccess(data)); // set books
    
    // Here, you can dispatch another action with newly updated state.
    const books = yield select(state => state.books);

    // I know you can just use 'data' variable here,
    // but let's say you have to update store first.
    yield put(anotherAction(books)); 
  } catch (error) {
    yield put(fetchBooksFailure(error)); // set error
  }
}

我试图用 createAsyncThunk 编写相同的代码,结果如下所示。

export const fetchBooks = createAsyncThunk(
  'BOOKS/FETCH_BOOKS',
  async (params, ThunkAPI) => {
    try {
      // when 'fetchBooks' is dispatched, fetchBooks.pending will be dispatched automatically.
      const { keyword } = ThunkAPI.getState(); // get keyword from store.
      const { data } = await SearchBooksAPI(query); // fetch books
      ThunkAPI.dispatch(fetchBooks.fulfilled(data)); // set books
      
      // store updated at this moment

      const { books } = ThunkAPI.getState();
      ThunkAPI.dispatch(anotherAction(books));
      
      // NOPE - returning value here will dispatch fetchBooks.fulfilled again.
      return data;
    } catch (error) {
      ThunkAPI.rejectWithValue(error); // dispatch fetchBooks.rejected
    }
  }
);

就像它的名字一样,payload creator 应该创建一个 payload。所以很明显我应该 return 有效载荷创建者中的一些东西。但在这种情况下,returning 值将再次发送 asyncAction.fulfilled,returned 值被 Promise 包装为有效负载。

我可以只使用普通的 thunk 动作或 saga,但我尝试这种方式的原因是尽量减少样板文件。使用普通的 thunk 动作将需要为 pending/success/failure 创建动作创建者,而使用 createAsyncThunk.

时则不需要

有没有人知道可以帮助我解决这个问题?任何意见将不胜感激。感谢阅读。

createAsyncThunk 并不完全适用于该用例。它专门用于处理“获取数据和调度结果”用例,而不是正在进行的调度序列。

可以访问有效负载创建回调中的thunkAPI.dispatch,因此您可以在 fulfilled 动作已调度。但是,fulfilled 操作在返回的 promise 解析之前不会被调度,因此它不会让您能够在 完成后调度更多操作。

目前我能想到的最接近的事情是这样的:

export const fetchBooks = createAsyncThunk(
  'BOOKS/FETCH_BOOKS',
  async (params, ThunkAPI) => {
    try {
      // when 'fetchBooks' is dispatched, fetchBooks.pending will be dispatched automatically.
      const { keyword } = ThunkAPI.getState(); // get keyword from store.
      const { data } = await SearchBooksAPI(query); // fetch books
      
      const resultPromise = Promise.resolve(data);
      
      resultPromise.then(() => {
        const { books } = ThunkAPI.getState();
        ThunkAPI.dispatch(anotherAction(books));
      })
      
      return resultPromise;
    } catch (error) {
      ThunkAPI.rejectWithValue(error); // dispatch fetchBooks.rejected
    }
  }
);

但我不确定承诺何时解决以及 fulfilled 操作何时被调度时的时间是否完全正确。

我认为您最好的选择是将其分成两个 thunk:一个只对原始数据执行正常的获取 + 调度,第二个 thunk 调度第一个,然后执行其他逻辑。