来记录学习reduxToolkit的过程。
一. 安装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
这只是最基础的使用,更多使用方法直接看官方文档吧
在类组件中使用
不会用,有没有大佬来告诉一下怎么在类组件用这个
学习文章链接