react-redux
使用心得
- 避免使用
connect函式,改用useSelector和useDispatch - 能很好的支持 redux 浏览器插件
- 不可以直接修改状态
- 异步处理相对复杂
安装
ts声明处理
ts
import counterReducer from '@/features/counter/counterSlice';
import { combineReducers, configureStore } from '@reduxjs/toolkit';
const rootReducer = combineReducers({
counter: counterReducer,
// ...其他 reducers
});
export type RootState = ReturnType<typeof rootReducer>;
export default configureStore({
reducer: rootReducer,
});扩展
异步请求(方法1)
tsx
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
// 创建异步 action
export const getList = createAsyncThunk('counter/getList', async (_, { rejectWithValue }) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ name: 'zhangsan' });
}, 1000);
});
});
export const counterSlice = createSlice({
name: 'counter',
initialState: {
data: {},
loading: false,
},
extraReducers: (builder) => {
/** 方法1 */
builder
.addCase(getList.pending, (state) => {
state.loading = true;
})
.addCase(getList.fulfilled, (state, action) => {
state.data = action.payload;
state.loading = false;
})
.addCase(getList.rejected, (state) => {
state.loading = false;
});
/**
* 方法2
* addMatcher 是全局处理
* */
// builder.addMatcher(
// (action) => action.type.endsWith('/pending'),
// (state) => {
// state.loading = true;
// },
// );
// builder.addMatcher(
// (action) => action.type.endsWith('/fulfilled'),
// (state, action) => {
// if (action.type === 'counter/getList/fulfilled') {
// state.data = action.payload;
// }
// state.loading = false;
// },
// );
// builder.addMatcher(
// (action) => action.type.endsWith('/rejected'),
// (state) => {
// state.loading = false;
// },
// );
},
});
export default counterSlice.reducer;tsx
import { getList } from '@/features/counter/counterSlice';
import { RootState } from '@/store';
import { Spin } from 'antd';
import { useEffect } from 'react';
import { useSelector } from 'react-redux';
const About = () => {
const loading = useSelector((state: RootState) => state.counter.loading);
useEffect(() => {
dispatch(getList());
}, []);
return (
<div className="size-full">
<Spin spinning={loading}>{JSON.stringify(data)}</Spin>
</div>
);
};
export default About;异步请求(方法2)
ts
export const getList = () => async (dispatch) => {
return new Promise((resolve) => {
dispatch({ type: 'counter/setLoading', payload: true });
setTimeout(() => {
dispatch({ type: 'counter/setData', payload: { name: 'zhangsan' } });
dispatch({ type: 'counter/setLoading', payload: false });
resolve();
}, 1000);
});
};
export const counterSlice = createSlice({
name: 'counter',
initialState: {
data: {},
loading: false,
},
reducers: {
setData(state, { payload }) {
state.data = payload;
},
setLoading(state, { payload }) {
state.loading = payload;
},
},
});