前提条件
Redux Toolkit(RTK): 官方推荐编写Redux逻辑的方式,是一套工具的集合集,简化书写方式
。
- 简化 store 的配置方式
- 内置 immer 支持可变式状态修改
- 内置 thunk 更好的异步创建
react-redux:用来链接 Redux 和 React组件
的中间件。
安装
npm i @reduxjs/toolkit react-redux
浏览器插件 - Redux DevTools(推荐但不强制使用)
下载并启用插件
控制台找到redux选项
配置
目录结构
src 下创建 store,其中 index.ts/index.js 作为modules中所有store的集合
store/index.ts配置
import { configureStore } from '@reduxjs/toolkit'
const store = configureStore({
reducer: {},
})
// 后续使用useSelector时参数state的类型
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
export default store
index.ts 或 main.ts中注册store
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
// 添加如下
import store from './app/store'
import { Provider } from 'react-redux'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
至此已经全局注册了Redux
配置
同步配置
import { createSlice } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'
export interface CounterState {
value: number
}
const initialState: CounterState = {
value: 0,
}
export const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment: (state:CounterState) => {
state.value += 1
},
decrement: (state:CounterState) => {
state.value -= 1
},
},
})
export default counterSlice.reducer
异步配置
import { createSlice,createAsyncThunk } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'
export interface CounterState {
value: number
}
const initialState: CounterState = {
value: 0,
}
export const counterSlice = createSlice({
name: 'counter',
initialState,
// 同步操作
reducers: {
......
},
// 异步操作
extraReducers(builder){
// 这里的payload就是incrementAsync的返回值
builder.addCase(incrementAsync.fulfilled,(state,{payload})=>{
state.value += payload
})
}
})
// 定义异步函数
export const incrementAsync = createAsyncThunk<number>(
"incrementAsync",
async(p:number)=>{
const res = await new Promise<number>(r=>{
setTimeout(() => {
r(p)
}, 1000);
})
return res
})
export default counterSlice.reducer
store/index.ts 中注册
import { configureStore } from "@reduxjs/toolkit";
// 引入counterSlice.ts
import counterStore from "./modules/counterSlice";
const store = configureStore({
reducer:{
// 注册,注意名字要与counterSlice.ts中的name一致
counter:counterStore
}
})
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
export default store
再次查看Redux Tools工具,已经发现value
使用
// useSelect用于选择操作哪个store
// useDispatch用于生成实例,该实例可以调用reducers的function
import { useSelector, useDispatch } from "react-redux"
// 引入index中的RootState类型 js项目不需要
import { AppDispatch, RootState } from "@/store"
// 引入functions
import { decrement, increment, incrementAsync } from "@/store/modules/counterSlice"
const Demo = () => {
const count = useSelector((state: RootState) => state.counter.value)
const dispatch: AppDispatch = useDispatch() // 异步函数必须加AppDispatch类型,否则报错,同步可以不添加
return (
<>
<div className="navbar_top"></div>
<div>{count}</div>
<button onClick={() => dispatch(increment({ value: 2 }))}>+2</button>
<button onClick={() => dispatch(incrementAsync(2))}>+2</button>
<button onClick={() => dispatch(decrement())}>-1</button>
</>
)
}
export default Demo
操作后通过工具发现value已经改变