createAsyncThunk: отправка дополнительных действий после обновления хранилища с извлеченными данными в рамках того же создателя полезной нагрузки

#reactjs #redux #redux-saga #redux-thunk #redux-toolkit

#reactjs #сокращение #redux-сага #сокращение-thunk #redux-toolkit

Вопрос:

Я только начал использовать Redux Toolkit (RTK), и мне трудно найти правильный способ использования createAsyncThunk из RTK.

Итак, что я пытаюсь сделать, это

  1. отправка асинхронного действия, созданного createAsyncThunk
  2. обновить хранилище с помощью извлеченных данных,
  3. и отправить другое синхронное действие в рамках того же создателя полезной нагрузки.

Например, вы могли бы написать такой код, 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
    }
  }
);
 

Как и его имя, создатель полезной нагрузки должен создать полезную нагрузку. Таким образом, очевидно, что я должен вернуть что-то в создателе полезной нагрузки. Но в этом случае возвращаемое значение будет отправлено asyncAction.fulfilled снова, причем возвращаемое значение будет обернуто обещанием в качестве полезной нагрузки.

Я мог бы просто использовать обычный боевик или сагу, но причина, по которой я пытаюсь использовать этот способ, заключается в том, чтобы свести к минимуму шаблонность. Использование обычного действия thunk потребует создания создателей действий для ожидающих / успешных / неудачных действий, что не является необходимым при использовании createAsyncThunk .

Есть ли у кого-нибудь идея, которая могла бы помочь мне решить эту проблему? любые комментарии будут оценены по достоинству. Спасибо вам за чтение.

Ответ №1:

createAsyncThunk не совсем подходит для этого варианта использования. Он специально предназначен для обработки варианта использования «выборка данных и результат отправки», а не для непрерывной последовательности отправок.

У вас есть доступ к thunkAPI.dispatch внутренней части обратного вызова создания полезной нагрузки, поэтому вы можете отправлять дополнительные действия до fulfilled отправки действия. Но fulfilled действие не будет отправлено до тех пор, пока не будет выполнено возвращенное обещание, поэтому оно не дает вам возможности отправлять дополнительные действия после этого. сделано.

Ближайшая вещь, о которой я могу думать на данный момент, была бы чем-то вроде этого:

 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 действие будет отправлено.

Я думаю, что вашим лучшим вариантом здесь было бы разбить это на два блока: один, который выполняет только обычную выборку отправку исходных данных, и второй блок, который отправляет первый, а затем выполняет дополнительную логику.