redux
1. 使用案例
index.js
import { createStore, applyMiddleware, combineReducers } from 'redux';
import thunk from 'redux-thunk'
import CounterReducer from './counter';
import HomeReducer from './home';
const reducer = combineReducers({
counter: CounterReducer,
home: HomeReducer
})
const store = createStore(reducer, applyMiddleware(thunk));
export default store;
name/action.js
import * as actionTypes from './const'
import axios from 'axios'
export const changeBannersAction = (banners) => ({
type: actionTypes.CHANGE_BANNERS,
banners
})
export const changeRecommendsAction = (recommends) => ({
type: actionTypes.CHANGE_RECOMMENDS,
recommends
})
export const getHomeMultidataAction = (dispatch) => {
return (dispatch) => {
axios.get('http://123.207.32.32:8000/home/multidata').then(res => {
const banners = res.data.data.banner.list
const recommends = res.data.data.recommend.list
dispatch(changeBannersAction(banners))
dispatch(changeRecommendsAction(recommends))
})
}
}
name/const.js
export const CHANGE_BANNERS = 'changeBanners';
export const CHANGE_RECOMMENDS = 'changeRecommends';
name/index.js
import reducer from './reducer'
export * from './action';
export default reducer;
name/reducer.js
import * as types from './const';
const initialState = {
banners: [],
recommends: []
}
function reducer(state = initialState, action) {
switch (action.type) {
case types.CHANGE_BANNERS:
return {
...state,
banners: action.banners
}
case types.CHANGE_RECOMMENDS:
return {
...state,
recommends: action.recommends
}
default:
return state;
}
}
export default reducer;
counter/action.js
import * as actionTypes from './const'
export const addNumberAction = (number) => ({
type: actionTypes.ADD_NUMBER,
number
})
export const subNumberAction = (number) => ({
type: actionTypes.SUB_NUMBER,
number
})
counter/const.js
export const ADD_NUMBER = 'addNumber';
export const SUB_NUMBER = 'subNumber';
counter/index.js
import reducer from './reducer'
export * from './action';
export default reducer;
counter/reducer.js
import * as types from './const';
const initialState = {
count: 100
}
function reducer(state = initialState, action) {
switch (action.type) {
case types.ADD_NUMBER:
return {
...state,
count: state.count + action.number
}
case types.SUB_NUMBER:
return {
...state,
count: state.count - action.number
}
default:
return state;
}
}
export default reducer;
@reduxjs/toolkit
1. 使用案例
$ pnpm install @reduxjs/toolkit react-redux
├── package.json
├── pnpm-lock.yaml
├── public
│ ├── favicon.ico
│ └── index.html
└── src
├── App.js
├── index.js
└── store
├── index.js
└── user
└── index.js
App.js
- 函数式组件中使用了useDispatch, useSelector 替代了以前的 connect 写法
- useSelector第二个参数shallowEqual可以进行浅层比较,避免别的组件操作state状态发生改变导致组件重新渲染
import {memo, useEffect} from 'react'
import {shallowEqual, useDispatch, useSelector} from 'react-redux'
import {fetchGoodsInfoAction} from "@store/modules/home"
function Home() {
const dispatch = useDispatch()
const state = useSelector((state) => ({
goodsInfo: state.home.goodsInfo
}), shallowEqual)
useEffect(() => {
dispatch(fetchGoodsInfoAction())
}, [dispatch])
return (
<div>
<h1>Home</h1>
<div>{state.goodsInfo.title}</div>
<ul>
{
state.goodsInfo.list?.map((item) => (
<li key={item.id}>{item.image_url}</li>
))
}
</ul>
</div>
)
}
export default memo(Home)
index.js
- 仍然需要与 react-redux Provider 结合来使用
import React, {Suspense} from 'react';
import ReactDOM from 'react-dom/client';
import 'normalize.css';
import {HashRouter} from 'react-router-dom';
import {Provider} from 'react-redux';
import store from './store'
import App from '@/App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<Suspense callback={"loading"}>
<HashRouter>
<App/>
</HashRouter>
</Suspense>
</Provider>
</React.StrictMode>
);
store/index.js
- configureStore替代了createStore的写法
- home: homeReducer中的home是store模块的别名
import {configureStore} from '@reduxjs/toolkit';
import homeReducer from '@store/modules/home';
const store = configureStore({
reducer: {
home: homeReducer
}
})
export default store;
store/modules/index.js
- createSlice 来创建一个函数片段
- createAsyncThunk 来编写网络请求代码
- reducers中的方法放置在了userSlice.actions
- export default userSlice.reducer返回给store进行配置
import {createSlice, createAsyncThunk} from '@reduxjs/toolkit';
import {getGoodsInfo} from '@service/modules/home';
export const fetchGoodsInfoAction = createAsyncThunk("GoodsInfo",async () => {
return await getGoodsInfo()
})
const homeSlice = createSlice({
name: 'home',
initialState: {
goodsInfo: {}
},
reducers: {
changeGoodsInfo(state, action) {
state.goodsInfo = action.payload;
}
},
extraReducers: {
[fetchGoodsInfoAction.fulfilled]: (state, action) => {
console.log(action.payload);
state.goodsInfo = action.payload;
}
}
})
export const {changeGoodsInfo} = homeSlice.actions;
export default homeSlice.reducer;