使用Redux ToolKit简化了传统redux创建的流程及代码量;借助createReducer和createSlice这两个钩子函数让我们更轻易的CRDU全局状态,同时在中间件中默认配置了thunk。
yarn add @reduxjs/toolkit react-redux redux-logger
import {createSlice, Draft} from '@reduxjs/toolkit'
//store的类型
export type UserStore={
user: string
isLogin: boolean
text: string
}
//创建一个createSlice
const userStore = createSlice({
name: 'user',
initialState(){
return {
user: 'admin',
isLogin: false,
text: '未登录'
} as UserStore
},
reducers: {
login(state:Draft<UserStore>) {
state.isLogin=true
state.text='已登录'
},
logout (state:Draft<UserStore>) {
state.isLogin=false
state.text='未登录'
},
}
})
//返回actions和reducer
export const { login, logout } = userStore.actions
export default userStore.reducer
import {configureStore} from '@reduxjs/toolkit'
import logger from 'redux-logger';
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import countReducer from "./count";
import userReducer from './user'
export const store=configureStore({
reducer: {
count:countReducer,
user:userReducer
},
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(logger)
})
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
export const useAppDispatch = () => useDispatch<AppDispatch>()
import React from 'react';
import ReactDOM from 'react-dom/client';
import 'nprogress/nprogress.css';
import './style/index.css';
import {
BrowserRouter as Router,
} from 'react-router-dom';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { store } from './store';
import { Provider } from 'react-redux';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement,
);
root.render(
<Router>
<Provider store={store}>
<App/>
</Provider>
</Router>
);
reportWebVitals();
import React from 'react';
import { asyncIncrement, decremented, incremented, } from '../store/count';
import { login, logout } from '../store/user';
import { RootState, useAppDispatch, useAppSelector } from '../store';
type Props = {}
const Test: React.FC<Props> = (props) => {
const count = useAppSelector((state: RootState) => state.count.num);
const user = useAppSelector((state: RootState) => state.user);
const dispatch = useAppDispatch();
return (
<>
<div>test</div>
<div>{count}</div>
<div>{JSON.stringify(user)}</div>
<button onClick={() => dispatch(incremented(50))}>+50</button>
<button onClick={() => dispatch(decremented(100))}>-100</button>
<button onClick={() => {
dispatch(asyncIncrement("/test"));
}}>重置
</button>
<button onClick={() => dispatch(login())}>login</button>
<button onClick={() => dispatch(logout())}>logout</button>
</>
);
};
export default Test;
Redux ToolKit支持异步操作
import {
createAsyncThunk,
createSlice,
Draft,
PayloadAction
} from '@reduxjs/toolkit';
//mock一个请求
const ajax=(url:string)=>{
return new Promise((resolve,reject)=>{
if(url==='/test'){
setTimeout(()=>{
resolve({data:20})
},2000)
}
})
}
//定义异步任务
export const asyncIncrement = createAsyncThunk('counter', async (url:string) => {
return await ajax(url) as {data:number};
});
//store的类型
export type CountStore = {
num: number
}
//创建一个store切片
const countStore = createSlice({
name: 'counter',
initialState() {
return {
num: 0
} as CountStore
},
reducers: {
incremented(state: Draft<CountStore>, action: PayloadAction<number>){
state.num += action.payload
},
decremented(state: Draft<CountStore>, action: PayloadAction<number>) {
state.num -= action.payload
}
},
extraReducers: (builder) => { //异步任务
builder.addCase(asyncIncrement.fulfilled, (state, action) => {
state.num=action.payload.data
})
},
})
//actions
export const {incremented, decremented} = countStore.actions
export default countStore.reducer