如何在 Redux Toolkit 的 createSlice 中使用 Redux-Thunk? [英] How to use Redux-Thunk with Redux Toolkit's createSlice?

查看:166
本文介绍了如何在 Redux Toolkit 的 createSlice 中使用 Redux-Thunk?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

@markerikson(请参阅已接受的答案)亲切地指出了当前的解决方案和未来的解决方案.

2020 年 11 月 15 日:链接到文档以在 Slice 中使用异步 Thunk

RTK 确实支持使用 thunk 中间件的 reducer 中的 thunk(参见答案).

在 1.3.0 版本(目前是 2020 年 2 月的 alpha 版)中,有一个辅助方法 createAsyncThunk() createAsyncThunk 将提供一些有用的功能(即根据状态触发 3 个扩展"减速器承诺).

ReduxJS/Toolkit NPM 发布

======================2020 年 2 月的原始帖子 ===========================

我对 Redux 还很陌生,遇到了 Redux Toolkit (RTK),并希望实现它提供的更多功能(或者在这种情况下可能没有?)(2020 年 2 月)

我的应用程序分派到通过 createSlice({}) 创建的 reducers 切片(请参阅 createSlice api 文档)

到目前为止,这非常有效.我可以轻松地使用内置的 dispatch(action)useSelector(selector) 来调度动作并在我的组件中很好地接收/响应状态变化.

我想使用 axios 的异步调用从 API 获取数据并在请求 A) 开始 B) 完成时更新存储.

我见过redux-thunk,它似乎完全是为此目的而设计的……但是新的RTKstrong> 似乎不支持它的 createSlice() 遵循一般谷歌搜索.

以上是用切片实现 thunk 的当前状态吗?

我在文档中看到您可以将 extraReducers 添加到切片,但不确定这是否意味着我可以创建更多传统减速器使用 thunk 并让切片实现它们?

总的来说,它具有误导性,因为 RTK 文档显示您可以使用 thunk...但似乎没有提到它不能通过新的 slices api 访问.

来自 Redux 工具包中间件的示例

const store = configureStore({减速器:rootReducer,中间件:[thunk,记录器]})

我的切片代码显示异步调用失败的位置以及其他一些可以工作的示例减速器.

import { getAxiosInstance } from '../../conf/index';导出 const slice = createSlice({name: '捆绑',初始状态:{捆绑: [],selectedBundle:空,页: {页数:0,总元素:0,尺寸:20,总页数:0},myAsyncResponse: 空},减速器:{//使用新的包和 Spring Page 对象更新状态.recievedBundlesFromAPI: (state, bundles) =>{console.log('正在获取捆绑包...');const springPage = bundles.payload.pageable;state.bundles = bundles.payload.content;状态.页面 = {页:springPage.pageNumber,大小:springPage.pageSize,totalElements: bundles.payload.totalElements,总页数:bundles.payload.totalPages};},//用户选择的Bundle.setSelectedBundle: (state, bundle) =>{console.log(`选定的 ${bundle} `);state.selectedBundle = 捆绑包;},//我想在这里使用/做一个异步函数......这失败了.myAsyncInSlice:(状态)=>{getAxiosInstance().得到('/').then((ok) => {state.myAsyncResponse = ok.data;}).catch((错误) => {state.myAsyncResponse = '错误';});}}});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;导出默认 slice.reducer;

我的商店设置(商店配置).

import { configureStore } from '@reduxjs/toolkit';从redux-thunk"导入 thunk;从'../slices/bundles-slice'导入bundlesReducer;从../slices/services-slice"导入 servicesReducer;从../slices/menu-slice"导入 menuReducer;从 '../slices/my-slice' 导入 mySliceReducer;const store = configureStore({减速器:{捆绑包:bundlesReducer,服务:servicesReducer,菜单:menuReducer,重定向:mySliceReducer}});导出默认商店;

不胜感激任何帮助或进一步的指导.

解决方案

我是 Redux 的维护者和 Redux Toolkit 的创建者.

FWIW,与使用 Redux Toolkit 更改 Redux 进行异步调用无关.

您仍然会使用异步中间件(通常是 redux-thunk),获取数据,并根据结果分发操作.

从 Redux Toolkit 1.3 开始,我们确实有一个名为 createAsyncThunk 生成动作创建者并为您请求生命周期动作分派,但它仍然是相同的标准流程.

文档中的示例代码总结了用法;

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'从 './userAPI' 导入 { userAPI }//首先,创建thunkconst fetchUserById = createAsyncThunk('用户/fetchByIdStatus',异步(用户 ID,thunkAPI)=>{const response = await userAPI.fetchById(userId)返回 response.data})//然后,在你的减速器中处理动作:const usersSlice = createSlice({名称:'用户',初始状态:{实体:[],加载:'空闲'},减速器:{//标准的减速器逻辑,每个减速器都有自动生成的动作类型},额外的减速器:{//在这里为其他动作类型添加reducer,并根据需要处理加载状态[fetchUserById.fulfilled]: (state, action) =>{//将用户添加到状态数组state.entities.push(action.payload)}}})//稍后,根据需要在应用程序中分派 thunk调度(fetchUserById(123))

请参阅 Redux 工具包使用指南":Async Logic and Data Fetching"文档页面,了解有关此主题的一些其他信息.

希望这为您指明了正确的方向!

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

@markerikson (see accepted answer) kindly pointed towards a current solution and a future solution.

EDIT: 15th Nov 2020: Link to Docs to use an Async Thunk in Slice

RTK does support thunks in reducers using the thunk middleware (see answer).

In 1.3.0 release (currently alpha in Feb 2020), there is a helper method createAsyncThunk() createAsyncThunk that will provide some useful functionality (i.e. triggers 3 'extended' reducers dependent on the state of the promise).

ReduxJS/Toolkit NPM releases

======================== Original Post Feb 2020 ==========================

I am quite new to Redux and have come across Redux Toolkit (RTK) and wanting to implement further functionality it provides (or in this case maybe doesn't?)(Feb 2020)

My application dispatches to reducers slices created via the createSlice({}) (see createSlice api docs)

This so far works brilliantly. I can easily use the built in dispatch(action) and useSelector(selector) to dispatch the actions and receive/react to the state changes well in my components.

I would like to use an async call from axios to fetch data from the API and update the store as the request is A) started B) completed.

I have seen redux-thunk and it seems as though it is designed entirely for this purpose...but the new RTK does not seem to support it within a createSlice() following general googling.

Is the above the current state of implementing thunk with slices?

I have seen in the docs that you can add extraReducers to the slice but unsure if this means I could create more traditional reducers that use thunk and have the slice implement them?

Overall, it is misleading as the RTK docs show you can use thunk...but doesn't seem to mention it not being accessible via the new slices api.

Example from Redux Tool Kit Middleware

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

My code for a slice showing where an async call would fail and some other example reducers that do work.

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;

My store setup (store config).

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;

Any help or further guidance would be greatly appreciated.

解决方案

I'm a Redux maintainer and creator of Redux Toolkit.

FWIW, nothing about making async calls with Redux changes with Redux Toolkit.

You'd still use an async middleware (typically redux-thunk), fetch data, and dispatch actions with the results.

As of Redux Toolkit 1.3, we do have a helper method called createAsyncThunk that generates the action creators and does request lifecycle action dispatching for you, but it's still the same standard process.

This sample code from the docs sums up the usage;

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))

See the Redux Toolkit "Usage Guide: Async Logic and Data Fetching" docs page for some additional info on this topic.

Hopefully that points you in the right direction!

这篇关于如何在 Redux Toolkit 的 createSlice 中使用 Redux-Thunk?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆