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

#redux #promise #es6-promise #redux-thunk #redux-toolkit

#сокращение #обещание #es6-обещание #сокращение-thunk #сокращение-инструментарий

Вопрос:

Мы откладываем рендеринг нашего веб-приложения React-Redux до тех пор, пока не будут выполнены несколько задач инициализации асинхронного приложения в Redux Store.

Вот код, который настраивает хранилище, а затем запускает действие инициализации:

 export const setupStoreAsync = () => {
    return new Promise((resolve, reject) => {
        const store = setupStore()
        store
            .dispatch(fetchAppInitialization())
            .then(unwrapResult)
            .then(_ => resolve(store))
            .catch(e => reject(e.message))
    })
}
  

Отклонение обещания очень важно, поскольку оно используется для отображения сообщения об ошибке для пользователя в случае, если приложение не может быть настроено должным образом. Этот код очень приятен для чтения и прекрасно работает.

Проблема в создателе действия:

 export const fetchAppInitialization = createAsyncThunk(
    'app/initialization',
    (_, thunkApi) =>
        new Promise((resolve, reject) =>
            Promise.all([thunkApi.dispatch(fetchVersionInfo())]).then(results => {
                results.map(result => result.action.error amp;amp; reject(result.error))
            })
        )
)
  

Этот код работает прекрасно. Если какое-либо из этих действий завершается неудачей, обещание отклоняется, и пользователь видит сообщение об ошибке. Но это некрасиво — это не так красиво, как наши обычные создатели действий:

 export const fetchVersionInfo = createAction('system/versionInfo', _ => ({
    payload: {
        request: { url: `/system/versionInfo` },
    },
}))
  

В какой-то момент мы запустим более одного запроса на выборку fetchAppInitialization , поэтому Promise.all функция определенно требуется. Мы хотели бы иметь возможность использовать createAction синтаксис Redux-Toolkit для запуска нескольких обещанных действий, чтобы сократить этот action creator, но я понятия не имею, возможно ли это вообще.

Примечание: Я использую redux-requests для обработки своих запросов axios.

createAsyncThunk Даже требуется?

Комментарии:

1. Используете ли вы вообще результирующие действия жизненного цикла? Если нет, то да, вы немного переусердствовали и могли бы просто переместить это в свой setupStoreAsync с помощью .catch 😉

Ответ №1:

Поскольку я не использовал fetchAppInitialization действие ни для чего, кроме этого единственного варианта использования, я просто удалил его и переместил логику прямо в setupStoreAsync функцию. Это немного более компактно. Это не оптимально, поскольку results.map логика все еще включена, но, по крайней мере, мы больше не используем createAsyncThunk .

 export const setupStoreAsync = () => {
    return new Promise((resolve, reject) => {
        const store = setupStore()

        new Promise((resolve, reject) =>
            Promise.all([store.dispatch(fetchVersionInfo())]).then(results => {
                results.map(result => result.action.error amp;amp; reject(result.error))
                resolve()
            })
        )
            .then(_ => resolve(store))
            .catch(e => reject(e.message))
    })
}
  

Обновление: я смог сделать код еще красивее с помощью async/await .

 export const setupStoreAsync = async () => {
    const store = setupStore()

    const results = await Promise.all([store.dispatch(fetchVersionInfo())])
    results.forEach(result => {
        if (result.action.error) throw result.error
    })
    return store
}
  

Комментарии:

1. Обратите внимание, что вы, вероятно, могли бы сократить эту логику, используя async/await вместо new Promise .