react|redux状态管理
参考官网:https://cn.redux-toolkit.js.org/tutorials/quick-start
状态管理使用流程
1、安装:
npm install react-redux @reduxjs/toolkit
2、创建store.js
通过configureStore的hook对reducer(或slice)进行统一管理。
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from '../features/counter/counterSlice';
export const store = configureStore({
reducer: {
counter: counterReducer,
// ...
},
});
3、编写我们的Reducer(或slice)
通过createSlice创建slice;需要创建异步的action方法的时候需要引入createAsyncThunk的hook。
createSlice核心属性:name、initialState、reducers、extraReducers。
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import { fetchCount } from './counterAPI';
const initialState = {
value: 0,
status: 'idle',
};
// 下面的函数称为thunk,它允许我们执行异步逻辑。
// 它可以像常规操作一样被调度:'dispatch(incrementAsync(10))'。
// 这将使用'dispatch'函数作为第一个参数来调用thunk。
// 然后可以执行异步代码,并可以分派其他操作。
// Thunks 通常用于发出异步请求.
export const incrementAsync = createAsyncThunk(
'counter/fetchCount',
async (amount) => {
const response = await fetchCount(amount);
// 我们返回的值成为“已完成”的操作负载(action.payload)
return response.data;
}
);
export const counterSlice = createSlice({
name: 'counter',
initialState,
// 'reducers'字段允许我们定义reducers并生成相关的操作(action)
reducers: {
increment: (state) => {
// Redux Toolkit允许我们在reducer中编写“状态变化”的逻辑。
// 它实际上不会改变状态,因为它使用了Immer库,
// 它检测到“状态”的变化,并根据这些变化产生一个全新的不可变状态
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
// 使用PayloadAction类型来声明' action.payload '的内容。
incrementByAmount: (state, action) => {
state.value += action.payload;
},
},
// 'extraReducers'字段允许切片处理在其他地方定义的动作,
// 包括由createAsyncThunk或其他切片生成的动作。
extraReducers: (builder) => {
builder
.addCase(incrementAsync.pending, (state) => {
state.status = 'loading';
})
.addCase(incrementAsync.fulfilled, (state, action) => {
state.status = 'idle';
state.value += action.payload;
});
},
});
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
// 下面的函数被称为选择器,它允许我们从状态中选择一个值。
// 选择器也可以内联定义,而不是在片文件中使用。
// 比如: `useSelector((state: RootState) => state.counter.value)`
export const selectCount = (state) => state.counter.value;
// 我们也可以手工编写脚本,其中可能包含同步和异步逻辑。
// 下面是一个基于当前状态有条件地调度操作的示例。
export const incrementIfOdd = (amount) => (dispatch, getState) => {
const currentValue = selectCount(getState());
if (currentValue % 2 === 1) {
dispatch(incrementByAmount(amount));
}
};
export default counterSlice.reducer;
4、提供redux store给react
使用Provider高阶组件包裹App,并传递store属性。
import React from 'react'
import ReactDOM from 'react-dom/client'
import './index.css'
import App from './App'
// 提供redux store给react,需要引入的工具store、provider
import store from './app/store'
import { Provider } from 'react-redux'
// As of React 18
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
<Provider store={store}>
<App />
</Provider>
)
5、react组件中操作redux的state和action
通过redux提供的useSelector和useDispatch的hook去操作state和action即可。
import './App.css';
import { useSelector, useDispatch } from 'react-redux';
import { incremented, decremented } from './store/slices/counterSlice';
function App() {
const count = useSelector((state) => {
return state.value;
});
const dispatch = useDispatch();
return (
<div className="App">
<header className="App-header">
<h3>count: {count}</h3>
<div>
<button style={{
width: '130px',
height: '40px',
fontSize: '20px',
cursor: 'pointer',
marginRight: '10px'
}} onClick={() => dispatch(incremented())}>incremented</button>
<button style={{
width: '130px',
height: '40px',
cursor: 'pointer',
fontSize: '20px'
}} onClick={() => dispatch(decremented())}>decremented</button>
</div>
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
</header>
</div>
);
}
export default App;