如何使用Redux工具包&x27;什么是createSlice?

如何使用Redux工具包&x27;什么是createSlice?,redux,redux-thunk,redux-toolkit,Redux,Redux Thunk,Redux Toolkit,======================TLDR========================== @markerikson(见接受的答案)善意地指出了当前的解决方案和未来的解决方案 编辑:2020年11月15日: RTK确实支持使用thunk中间件的Reducer中的thunk(参见答案) 在1.3.0版本(目前alpha于2020年2月发布)中,有一个助手方法createAsyncThunk(),它将提供一些有用的功能(即触发3个“扩展”还原器,具体取决于承诺的状态) =======

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

@markerikson(见接受的答案)善意地指出了当前的解决方案和未来的解决方案

编辑:2020年11月15日:

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

在1.3.0版本(目前alpha于2020年2月发布)中,有一个助手方法
createAsyncThunk()
,它将提供一些有用的功能(即触发3个“扩展”还原器,具体取决于承诺的状态)

========================================原2020年2月后==========================

我对Redux很陌生,遇到过Redux工具包(RTK),希望实现它提供的进一步功能(或者在这种情况下可能没有?)(2020年2月)

我的应用程序将调度到通过
createSlice({})
创建的还原程序切片(请参阅)

到目前为止,这项工作非常出色。我可以轻松地使用内置的
分派(操作)
使用选择器(选择器)
分派操作,并很好地接收/响应组件中的状态更改

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

我看到过redux thunk,它似乎完全是为了这个目的而设计的……但是新的RTK似乎不支持在谷歌搜索之后的
createSlice()
中使用它

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

我在文档中看到,您可以向切片中添加外部还原程序,但不确定这是否意味着我可以创建更多使用thunk的传统还原程序,并让切片实现它们

总的来说,RTK文档显示您可以使用thunk,这是一个误导,但似乎没有提到它不能通过新的slices api访问

来自

我的代码是一个片段,显示异步调用失败的地方,以及其他一些可以工作的示例还原程序

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;
我的商店设置(商店配置)


如有任何帮助或进一步指导,将不胜感激。

使用
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;
    },
  },
});



我是Redux的维护者和Redux工具包的创建者

FWIW,没有关于使用Redux工具箱进行异步调用的内容

您仍然可以使用异步中间件(通常),获取数据,并根据结果分派操作

从Redux Toolkit 1.3开始,我们有一个名为的助手方法,它生成动作创建者,并为您请求生命周期动作调度,但它仍然是相同的标准过程

文档中的示例代码总结了使用情况

从'@reduxjs/toolkit'导入{createAsynchThunk,createSlice}
从“/userAPI”导入{userAPI}
//首先,创建thunk
const fetchUserById=createAsynchThunk(
“用户/fetchByIdStatus”,
异步(用户ID,thunkAPI)=>{
const response=await userAPI.fetchById(userId)
返回响应.data
}
)
//然后,在减速器中处理操作:
const usersSlice=createSlice({
名称:'用户',
initialState:{entities:[],正在加载:'idle'},
减速器:{
//标准减速器逻辑,每个减速器自动生成动作类型
},
外减速器:{
//在此处为其他操作类型添加还原器,并根据需要处理加载状态
[fetchUserById.Completed]:(状态、操作)=>{
//将用户添加到状态数组
state.entities.push(action.payload)
}
}
})
//稍后,根据需要在应用程序中发送thunk
分派(fetchUserById(123))
有关此主题的更多信息,请参阅


希望这能为你指明正确的方向

您可以使用
createAsyncThunk
创建
thunk操作
,可以使用
dispatch

teamSlice.ts

import {
  createSlice,
  createAsyncThunk,
} from "@reduxjs/toolkit";
const axios = require('axios');

export const fetchPlayerList = createAsyncThunk('team/playerListLoading', 
  (teamId:string) =>
  axios
    .get(`https://api.opendota.com/api/teams/${teamId}/players`)
    .then(response => response.data)
    .catch(error => error),
);

const teamInitialState = {
   playerList: {
     status: 'idle',
     data: {},
     error: {}
   }    
};

const teamSlice = createSlice({
  name: 'user',
  initialState: teamInitialState,
  reducers: {},
  extraReducers: {
    [fetchPlayerList.pending.type]: (state, action) => {
        state.playerList = {
        status: 'loading',
        data: {},
        error: {}
      };
    },
    [fetchPlayerList.fulfilled.type]: (state, action) => {
        state.playerList = {
        status: 'idle',
        data: action.payload,
        error: {}
     };
    },
    [fetchPlayerList.rejected.type]: (state, action) => {
        state.playerList = {
        status: 'idle',
        data: {},
        error: action.payload,
      };
    },
  }
});

export default teamSlice;
Team.tsx组件

import React from "react";
import { useSelector, useDispatch } from "react-redux";

import { fetchPlayerList } from './teamSlice';

const Team = (props) => {
  const dispatch = useDispatch();
  const playerList = useSelector((state: any) => state.team.playerList);

  return (
    <div>
      <button
        onClick={() => { dispatch(fetchPlayerList('1838315')); }}
      >Fetch Team players</button>

      <p>API status {playerList.status}</p>
      <div>
        { (playerList.status !== 'loading' && playerList.data.length) &&
          playerList.data.map((player) => 
            <div style={{display: 'flex'}}>
              <p>Name: {player.name}</p>
              <p>Games Played: {player.games_played}</p>
            </div>
          )
        }
      </div>
    </div>
  )
}

export default Team;
从“React”导入React;
从“react-redux”导入{useSelector,useDispatch};
从“/teamSlice”导入{fetchPlayerList};
const团队=(道具)=>{
const dispatch=usedpatch();
constplayerlist=useSelector((state:any)=>state.team.playerList);
返回(
{dispatch(fetchPlayerList('1838315');}
>召集队员
API状态{playerList.status}

{(playerList.status!='loading'&&playerList.data.length)&& playerList.data.map((player)=> 名称:{player.Name}

玩过的游戏:{玩家。玩过的游戏}

) } ) } 导出默认团队;
谢谢。我曾看到您对Git问题发表评论,但由于它仍然是开放的,我认为还没有实现(因此没有进一步冒险)。顺便说一句,工作做得很棒,等不及下一个主要版本了!我主要是一名Spring Boot后端开发人员,作为一名新手,整个前端世界让我头晕目眩,但您的工作使它非常易于理解和使用。也许我应该看看“高级”,但在做了几天的redux(和RTK的几个小时)之后,我并没有走那么远哈!太好了,谢谢你的积极反馈!是的,RTK文档目前是在假设您已经知道Redux是如何工作的情况下编写的,因此他们重点解释使用RTK与“手工”编写Redux逻辑的不同之处。在RTK1.3.0之后,我的下一个任务是添加一个新的Redux核心文档“快速入门”页面,该页面假设您是Redux新手,并展示了从零开始使用RTK编写Redux代码的最简单方法。这将是完美的。我发现自己潜入了前端的世界……在两周的时间里,我经历了以下的演变:1。仅对生命周期和状态进行反应。2.使用lifecycle、redux和MaterialUI。3.机智
import {
  createSlice,
  createAsyncThunk,
} from "@reduxjs/toolkit";
const axios = require('axios');

export const fetchPlayerList = createAsyncThunk('team/playerListLoading', 
  (teamId:string) =>
  axios
    .get(`https://api.opendota.com/api/teams/${teamId}/players`)
    .then(response => response.data)
    .catch(error => error),
);

const teamInitialState = {
   playerList: {
     status: 'idle',
     data: {},
     error: {}
   }    
};

const teamSlice = createSlice({
  name: 'user',
  initialState: teamInitialState,
  reducers: {},
  extraReducers: {
    [fetchPlayerList.pending.type]: (state, action) => {
        state.playerList = {
        status: 'loading',
        data: {},
        error: {}
      };
    },
    [fetchPlayerList.fulfilled.type]: (state, action) => {
        state.playerList = {
        status: 'idle',
        data: action.payload,
        error: {}
     };
    },
    [fetchPlayerList.rejected.type]: (state, action) => {
        state.playerList = {
        status: 'idle',
        data: {},
        error: action.payload,
      };
    },
  }
});

export default teamSlice;
import React from "react";
import { useSelector, useDispatch } from "react-redux";

import { fetchPlayerList } from './teamSlice';

const Team = (props) => {
  const dispatch = useDispatch();
  const playerList = useSelector((state: any) => state.team.playerList);

  return (
    <div>
      <button
        onClick={() => { dispatch(fetchPlayerList('1838315')); }}
      >Fetch Team players</button>

      <p>API status {playerList.status}</p>
      <div>
        { (playerList.status !== 'loading' && playerList.data.length) &&
          playerList.data.map((player) => 
            <div style={{display: 'flex'}}>
              <p>Name: {player.name}</p>
              <p>Games Played: {player.games_played}</p>
            </div>
          )
        }
      </div>
    </div>
  )
}

export default Team;