reduxToolkit学习笔记

206 阅读5分钟

来记录学习reduxToolkit的过程。

redux中文文档

一. 安装RTK

yarn add @reduxjs/toolkit react-redux

二. 开始创建store

1.在src新建一个store文件夹

2.在store文件夹内创建一个festures文件夹,用来存放slice,新建一个userSlice.ts

//userSlice.ts
import {createAsyncThunk, createSlice} from '@reduxjs/toolkit'
export interface userState{
    userInfo:{
        name:string
        age:number
    }
}
const initialState:userState = {
    userInfo:{name:'',age:0}
}

export const userSlice=createSlice({
    name:'user',
    initialState,
    reducers:{
        setUserInfoName:(state)=>{
            state.userInfo.name = 'wyt'
        },
        setUserInfoAge:(state,{payload})=>{
            state.userInfo.name = 'wyt'
        }
    }
})
export const {setUserInfoName} =userSlice.actions;
export default userSlice.reducer

RTK中的createSlice函数返回一个带有以下属性的对象:

  • name:切片的名称。
  • initialState:切片的初始值。
  • reducer:包含更新状态逻辑的reducer函数。

放在reducer里的函数,可以直接改变initialState对象的属性

放在reducer里的函数,接收两个参数,第一个参数是当前的状态(state),第二个参数是一个 action,包含 type 和 payload 两个属性

3.在store文件夹内新建index.ts,使用configureStore来创建一个store

//index.ts
import { configureStore } from "@reduxjs/toolkit"; 
import counterSlice from "./features/userSlice.ts"; 
// configureStore创建一个store
const store = configureStore({ 
    // 合并多个Slice 
    reducer: { 
        counter: counterSlice 
    }, 
});
export default store;

4.使用我们的store

在src的index文件中引入Provider,把我们创建的store传入

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import store from './store';
const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

三. 开始使用

1.在类组件中使用

在类组件中使用时需要使用connect

import {connect} from 'react-redux'
import {setUserInfoName,setUserInfoAge} from '@/store/festures/userSlice'
interface IIndexProps{
    userInfo:any
    setUserInfoName:()=>void
    setUserInfoAge:(obj:any)=>void
}
class Index extends Component<IIndexProps,any> {
    render() {
        const {
            userInfo,
            setUserInfoName,
            setUserInfoAge,
        } = this.props
        return (
            <div>
                <p>name:{userInfo.name}</p>
                <p>age:{userInfo.age}</p>
                <button onClick={()=>{
                    setUserInfoName()
                }}>获取名称</button>
                <button onClick={()=>{
                    setUserInfoAge({age:18})
                }}>获取年龄</button>
            </div>
        );
    }
}
const mapStateToProps = (state:any) => {
    return {
        userInfo: state.user.userInfo
    }
}
const mapDispatchToProps = {setUserInfoName,setUserInfoAge}
export default connect(mapStateToProps, mapDispatchToProps)(Index);

2. 在函数组件中使用

import React,{FC} from 'react'
import {useSelector, useDispatch} from 'react-redux';
import {setUserInfoName} from '@/store/festures/userSlice'
const Child:FC<any> = (props:any)=>{
    const {userInfo} = useSelector((store:any)=>store.user)
    const dispatch = useDispatch()
    return <div>
            <div>函数组件名称:{userInfo.name}</div>
            <button onClick={()=>{dispatch(setUserInfoName())}}>函数组件获取名称</button>
        </div>
}
export default Child

四. 异步请求

1. 使用createAsyncThunk

createAsyncThunk 可以创建一个异步action,通常用于发出异步请求。方法触发的时候会有三种状态:pending(进行中)、fulfilled(成功)、rejected(失败)

extraReducers 可以让 slice 处理在别处定义的 actions,包括由 createAsyncThunk 或其他 slice 生成的 actions

//userSlice.ts
import {createAsyncThunk, createSlice} from '@reduxjs/toolkit'
export interface userState{
    userInfo:{
        name:string,
        age:number
    }
}
const initialState:userState = {
    userInfo:{name:'',age:0}
}
const getUserApi = ()=>{
    return new Promise((resolve)=>{
        setTimeout(()=>{
            resolve({
                code:200,
                data:{
                    name:'wangyuanti'
                }
            })
        },1000)
    })
}
export const getUserData=createAsyncThunk('user/getUser',async ()=>{
    const res = await getUserApi()
    return res
})
export const userSlice=createSlice({
    name:'user',
    initialState,
    reducers:{
        setUserInfoName:(state)=>{
            state.userInfo.name = 'wyt'
        },
        setUserInfoAge:(state,{payload})=>{
            state.userInfo.age = payload.age
        }
    },
    extraReducers(builder) {
        builder
        .addCase(getUserData.pending,()=>{
        })
        .addCase(getUserData.fulfilled,(state, {payload}:{payload:any})=>{
            state.userInfo.name=payload?.data.name
            console.log(state.userInfo.name)
        })
    },
})
export const {setUserInfoName,setUserInfoAge} =userSlice.actions;
export default userSlice.reducer

在页面使用

  • 类组件
import React, { Component } from 'react';
import {connect} from 'react-redux'
import {setUserInfoName,setUserInfoAge,getUserData} from '@/store/festures/userSlice'
interface IIndexProps{
    userInfo:any
    setUserInfoName:()=>void
    getUserData:()=>void
    setUserInfoAge:(obj:any)=>void
}
class Index extends Component<IIndexProps,any> {
    render() {
        const {
            userInfo,
            setUserInfoName,
            setUserInfoAge,
            getUserData
        } = this.props
        return (
            <div>
                <p>name:{userInfo.name}</p>
                <p>age:{userInfo.age}</p>
                <button onClick={()=>{
                    setUserInfoName()
                }}>获取名称</button>
                <button onClick={()=>{
                    setUserInfoAge({age:18})
                }}>获取年龄</button>
                <button onClick={()=>{
                    getUserData()
                }}>createAsyncThunk获取名称</button>
            </div>
        );
    }
}
const mapStateToProps = (state:any) => {
    return {
        userInfo: state.user.userInfo
    }
}

const mapDispatchToProps = {setUserInfoName,setUserInfoAge,getUserData}
export default connect(mapStateToProps, mapDispatchToProps)(Index);
  • 函数组件
import React,{FC} from 'react'
import {useSelector, useDispatch} from 'react-redux';
import {setUserInfoName,getUserData} from '@/store/festures/userSlice'
const Child:FC<any> = (props:any)=>{
    const {userInfo} = useSelector((store:any)=>store.user)
    const dispatch = useDispatch()
    return <div>
            <div>函数组件名称:{userInfo.name}</div>
            <button onClick={()=>{dispatch(setUserInfoName())}}>函数组件获取名称</button>
            <button onClick={()=>{dispatch(getUserData())}}>函数组件createAsyncThunk获取名称</button>
        </div>
}
export default Child

这么写有个问题 用ts的时候*dispatch(getUserData())*会报错

类型“AsyncThunkAction<unknown, void, AsyncThunkConfig>”的参数不能赋给类型“AnyAction”的参数。

我们需要修改一下之前的文件

首先在store的index.tsx中导出两个类型 RootState、AppDispatch

//index.ts
    import { configureStore } from "@reduxjs/toolkit"; 
    import counterSlice from "./features/userSlice.ts"; 
    // configureStore创建一个store
    const store = configureStore({ 
        // 合并多个Slice 
        reducer: { 
            counter: counterSlice 
        }, 
    });
    
    export type RootState = ReturnType<typeof store.getState>
    export type AppDispatch = typeof store.dispatch
    export default store; 

之后新建一个hooks.ts文件

//hooks.ts文
//此处对redux中的useDispatch, useSelector 进行二次封装方便项目中调用
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { AppDispatch, RootState } from './index'
export const useAppDispatch = () => useDispatch<AppDispatch>()
export const useAppSelector : TypedUseSelectorHook<RootState> = useSelector

然后再函数组件使用

import React,{FC} from 'react'
// import {useSelector, useDispatch} from 'react-redux';
import {setUserInfoName,getUserData} from '@/store/festures/userSlice'
import { useAppDispatch, useAppSelector } from '@/store/hooks';
const Child:FC<any> = (props:any)=>{
    // const {userInfo} = useSelector((store:any)=>store.user)
    // const dispatch = useDispatch()
    const {userInfo}  = useAppSelector(state => state.user);
    const dispatch = useAppDispatch(); 
    return <div>
            <div>函数组件名称:{userInfo.name}</div>
            <button onClick={()=>{dispatch(setUserInfoName())}}>函数组件获取名称</button>
            <button onClick={()=>{dispatch(getUserData() ) }}>函数组件createAsyncThunk获取名称</button>
        </div>
}
export default Child

2. 使用createApi

新建一个globalReducer.ts文件

//globalReducer.ts
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'

const globalReducer = createApi({
   // 这个reducerPath相当于我们 createSlice配置中的name
   reducerPath: 'globalReducer',
   // 配置一些异步请求 fetchBaseQuery是库内置的基于fetch封装的请求方法
   baseQuery: fetchBaseQuery({
    baseUrl: "https://www.fastmock.site/mock/5d21ead666216108f62f69e1c82a5579/list",
  }),
  
  // 配置你的异步方法
   endpoints: (builder) => {
     return {
       // 定义一个接口
       //从参数生成查询参数 转变响应并且缓存
       //React entry point 会自动根据endpoints生成hooks
       getTodos: builder.query({query: (params) => ({
          method: 'GET',
          url: `/api/getUser`,
          params
       })}),
       getPost: builder.mutation({query: (params) => ({
        method: 'POST',
        url: `/api/post`,
        params
     })}),
     }
   }
 })
 export const { useGetTodosQuery,useGetPostMutation } = globalReducer
export default globalReducer;

把globalReducer绑定到store

import {configureStore} from '@reduxjs/toolkit'
import { userSlice } from './festures'
import globalReducer from './globalReducer'
import globalReducer1 from './globalReducer1'
 const store = configureStore({
    reducer:{
        user:userSlice,
        [globalReducer.reducerPath]: globalReducer.reducer,
    },
    middleware:(getDefaultMiddleware)=>{
        return getDefaultMiddleware().concat([globalReducer.middleware])
    },
})
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
export default store;

在函数组件中使用 一进页面展示loading,接口返回后展示403

import React,{FC} from 'react'
// import {useSelector, useDispatch} from 'react-redux';
import {setUserInfoName,getUserData} from '@/store/festures/userSlice'
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import {useGetTodosQuery} from "@/store/globalReducer";
const Child:FC<any> = (props:any)=>{
    // const {userInfo} = useSelector((store:any)=>store.user)
    // const dispatch = useDispatch()
    const { isLoading, data, isError, isSuccess } = useGetTodosQuery({name:'wyt'})
    const {userInfo}  = useAppSelector(state => state.user);
    const dispatch = useAppDispatch(); 
    return <div>
            <div>函数组件名称:{userInfo.name}</div>
            <button onClick={()=>{dispatch(setUserInfoName())}}>函数组件获取名称</button>
            <button onClick={()=>{dispatch(getUserData() ) }}>函数组件createAsyncThunk获取名称</button>
            {isLoading ? <div>loading...</div> : <div>403......</div>}
        </div>
}
export default Child

这只是最基础的使用,更多使用方法直接看官方文档

在类组件中使用

不会用,有没有大佬来告诉一下怎么在类组件用这个

学习文章链接

blog.csdn.net/weixin_4562…

juejin.cn/post/710168…