Как использовать Redux-Thunk с createSlice Redux Toolkit? - PullRequest
3 голосов
/ 20 февраля 2020

==================== TLDR ==================== ======

@ markerikson (см. Принятый ответ) любезно указал на текущее решение и будущее решение.

RTK делает поддержка thunks в редукторах с использованием промежуточного программного обеспечения thunk (см. ответ).

В выпуске 1.3.0 ( в настоящее время альфа в феврале 2020 ) есть вспомогательный метод createAsyncThunk() createAsyncThunk , который обеспечит некоторую полезную функциональность (т.е. запускает 3 «расширенных» редуктора, зависящих от состояния обещания).

ReduxJS / Toolkit NPM релизы

======================== Исходное сообщение февраль 2020 ========= =================

Я довольно новичок в Redux и столкнулся с Redux Toolkit (RTK) и хочу реализовать дополнительные функции, которые он обеспечивает ( или в этом случае, может быть, нет?) (февраль 2020)

Мое приложение отправляет срезы редукторов, созданные с помощью createSlice({}) (см. cre ateSlice api docs )

Пока это работает блестяще. Я могу легко использовать встроенные dispatch(action) и useSelector(selector) для отправки действий и получения / реагирования на изменения состояния в моих компонентах.

Я хотел бы использовать вызов asyn c от ax ios для извлечения данных из API и обновления хранилища, поскольку запрос A) запущен B) завершен.

I видел redux-thunk и кажется, что он предназначен исключительно для этой цели ... но новый RTK не кажется, поддерживает его в пределах createSlice() после общего поиска в Google.

Вышеуказанное текущее состояние реализации thunk со слайсами?

Я видел в документах, что вы можете добавить extraReducers для среза, но не уверен, что это означает, что я мог бы создать больше традиционных редукторов, которые используют thunk и имеют срез, реализующих их?

В целом, это так вводит в заблуждение, как показывают документы RTK, вы можете использовать thunk ... но, похоже, не упоминаете, что он недоступен через API новых ломтиков.

Пример из Промежуточное ПО Redux Tool Kit

const store = configureStore({
  reducer: rootReducer,
  middleware: [thunk, logger]
})

Мой код для фрагмента, показывающего, где вызов asyn c будет сбой и некоторые другие примеры редукторов, которые работают.

import { getAxiosInstance } from '../../conf/index';

export const slice = createSlice({
    name: 'bundles',
    initialState: {
        bundles: [],
        selectedBundle: null,
        page: {
            page: 0,
            totalElements: 0,
            size: 20,
            totalPages: 0
        },
        myAsyncResponse: null
    },

    reducers: {
        //Update the state with the new bundles and the Spring Page object.
        recievedBundlesFromAPI: (state, bundles) => {
            console.log('Getting bundles...');
            const springPage = bundles.payload.pageable;
            state.bundles = bundles.payload.content;
            state.page = {
                page: springPage.pageNumber,
                size: springPage.pageSize,
                totalElements: bundles.payload.totalElements,
                totalPages: bundles.payload.totalPages
            };
        },

        //The Bundle selected by the user.
        setSelectedBundle: (state, bundle) => {
            console.log(`Selected ${bundle} `);
            state.selectedBundle = bundle;
        },

        //I WANT TO USE / DO AN ASYNC FUNCTION HERE...THIS FAILS.
        myAsyncInSlice: (state) => {
            getAxiosInstance()
                .get('/')
                .then((ok) => {
                    state.myAsyncResponse = ok.data;
                })
                .catch((err) => {
                    state.myAsyncResponse = 'ERROR';
                });
        }
    }
});

export const selectBundles = (state) => state.bundles.bundles;
export const selectedBundle = (state) => state.bundles.selectBundle;
export const selectPage = (state) => state.bundles.page;
export const { recievedBundlesFromAPI, setSelectedBundle, myAsyncInSlice } = slice.actions;
export default slice.reducer;

Настройка моего магазина (настройка магазина).

import { configureStore } from '@reduxjs/toolkit';
import thunk from 'redux-thunk';

import bundlesReducer from '../slices/bundles-slice';
import servicesReducer from '../slices/services-slice';
import menuReducer from '../slices/menu-slice';
import mySliceReducer from '../slices/my-slice';

const store = configureStore({
    reducer: {
        bundles: bundlesReducer,
        services: servicesReducer,
        menu: menuReducer,
        redirect: mySliceReducer
    }
});
export default store;

Любая помощь или дальнейшие указания будут с благодарностью.

Ответы [ 2 ]

14 голосов
/ 20 февраля 2020

Я поддерживаю Redux и создаю Redux Toolkit.

FWIW, я ничего не делаю в асинхронных c вызовах с изменениями Redux с помощью Redux Toolkit.

Вы по-прежнему используете asyn c middleware (обычно redux-thunk), выборка данных и действия по отправке с результатами.

Начиная с Redux Toolkit 1.3, у нас есть вспомогательный метод с именем createAsyncThunk, который генерирует создателей действий и запрашивает отправку действий жизненного цикла для вас, но это все тот же стандартный процесс.

Этот пример кода из документов подводит итог использования;

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
import { userAPI } from './userAPI'

// First, create the thunk
const fetchUserById = createAsyncThunk(
  'users/fetchByIdStatus',
  async (userId, thunkAPI) => {
    const response = await userAPI.fetchById(userId)
    return response.data
  }
)

// Then, handle actions in your reducers:
const usersSlice = createSlice({
  name: 'users',
  initialState: { entities: [], loading: 'idle' },
  reducers: {
    // standard reducer logic, with auto-generated action types per reducer
  },
  extraReducers: {
    // Add reducers for additional action types here, and handle loading state as needed
    [fetchUserById.fulfilled]: (state, action) => {
      // Add user to the state array
      state.entities.push(action.payload)
    }
  }
})

// Later, dispatch the thunk as needed in the app
dispatch(fetchUserById(123))

См. Руководство по использованию Redux Toolkit: Asyn c Logi c и Data Fetching "на странице документов для получения дополнительной информации по этой теме c.

Надеемся это указывает вам правильное направление!

3 голосов
/ 20 февраля 2020

Использование redux-toolkit v1.3.0-alpha.8

Попробуйте это

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';

export const myAsyncInSlice = createAsyncThunk('bundles/myAsyncInSlice', () =>
  getAxiosInstance()
    .get('/')
    .then(ok => ok.data)
    .catch(err => err),
);

const usersSlice = createSlice({
  name: 'bundles',
  initialState: {
    bundles: [],
    selectedBundle: null,
    page: {
      page: 0,
      totalElements: 0,
      size: 20,
      totalPages: 0,
    },
    myAsyncResponse: null,
    myAsyncResponseError: null,
  },
  reducers: {
    // add your non-async reducers here
  },
  extraReducers: {
    // you can mutate state directly, since it is using immer behind the scenes
    [myAsyncInSlice.fulfilled]: (state, action) => {
      state.myAsyncResponse = action.payload;
    },
    [myAsyncInSlice.rejected]: (state, action) => {
      state.myAsyncResponseError = action.payload;
    },
  },
});


...