随着 JavaScript 单页应用开发日趋复杂,JavaScript 需要管理比任何时候都要多的 state (状态) 。 这些 state 可能包括服务器响应、缓存数据、本地生成尚未持久化到服务器的数据,也包括 UI 状态,如激活的路由,被选中的标签,是否显示加载动效或者分页器等等。Redux基本概念主要有以下几个:
Store
Store就是一个仓库,它存储了所有的状态(State),还提供了一些操作他的API,我们后续的操作其实都是在操作这个仓库。
store 是应用状态 state 的管理者,包含下列四个函数:
getState() 获取整个 statedispatch(action) 触发 state 改变的唯一途径subscribe(listener) 可以理解成是 DOM 中的 addEventListenerreplaceReducer(nextReducer) 一般在 Webpack Code-Splitting 按需加载的时候用
state和store的关系:state = store.getState()
Actions
Action 是把数据从应用传到 store 的有效载荷。它是 store 数据的唯一来源。一般来说你会通过 store.dispatch() 将 action 传到 store。
一个Action就是一个动作,这个动作的目的是更改Store中的某个状态,Store还是上面的那个仓库,现在我想往书架放一本书,那"我想往书架放一本书"就是一个Action,代码就是这样:
{
type: "PUT_BOOK",
count: 1
}
Reducer
Reducers 指定了应用状态的变化如何响应actions并发送到 store 的,记住 actions 只是描述了有事情发生了这一事实,并没有描述应用如何更新 state。
正如前面"我想往往书架放一本书"只是想了,还没操作,具体操作要靠Reducer,Reducer就是根据接收的Action来改变Store中的状态,比如我接收了一个PUT_BOOK,同时数量count是1,那放进去的结果就是book增加了1,从0变成了1,代码就是这样:
function reducer(state = { book : 0 }, action) {
switch (action.type) {
case 'PUT_BOOK':
return {...state, book: state.book + action.count}
default:
return state
}
}
认识一下redux在实际开发中的流程:
在项目中使用redux
在src目录中新建store文件夹:
添加index.js文件:
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import reducer from "./reducer";
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk))); //合并中间件 applyMiddleware
export default store
添加reducer.js文件:
import { combineReducers } from "redux-immutable"; //合成reducer
import { reducer as recommendReducer } from "../pages/discover/c-pages/recommend/store";
import { reducer as playerReducer } from "../pages/player/store";
const cReducer = combineReducers({
recommend: recommendReducer,
player: playerReducer,
});
export default cReducer;
在项目目标page中添加store文件夹,方便管理:
新建actionCreators.js文件:
import * as actionTypes from "./constants";
import {
getTopBanners,
getHotRecommends,
} from "@/services/recommend"; //网络请求
const changeTopBannerAction = (res) => ({
type: actionTypes.CHANGE_TOP_BANNERS,
topBanners: res.banners,
});
const changeHotRecommendAction = (res) => ({
type: actionTypes.CHANGE_HOT_RECOMMEND,
hotRecommends: res.result,
});
export const getTopBannerAction = () => {
return (dispatch) => {
getTopBanners().then((res) => {
dispatch(changeTopBannerAction(res));
});
};
};
export const getHotRecommendAction = (limit) => {
return (dispatch) => {
getHotRecommends(limit).then((res) => {
dispatch(changeHotRecommendAction(res));
});
};
};
新建constants.js文件:
export const CHANGE_TOP_BANNERS = "recommend/CHANGE_TOP_BANNERS"
export const CHANGE_HOT_RECOMMEND = "recommend/CHANGE_HOT_RECOMMEND"
新建index.js文件(导出reducer):
import reducer from './reducer'
export {
reducer
}
新建reducer.js文件:
import { Map } from "immutable";
import * as actionTypes from "./constants";
const defaultState = Map({
topBanners: [],
hotRecommends: [],
});
function reducer(state = defaultState, action) {
switch (action.type) {
case actionTypes.CHANGE_TOP_BANNERS:
return state.set("topBanners", action.topBanners);
case actionTypes.CHANGE_HOT_RECOMMEND:
return state.set("hotRecommends", action.hotRecommends);
default:
return state;
}
}
export default reducer;
上述代码中的 immutable
1.一旦创建,就不能更改的数据,对immutable对象的任何修改或删除添加都会返回一个新的immutable对象
2.实现原理就是持久化数据结构,在使用旧数据创建新数据的时候,会保证旧数据同时可用且不变,同时为了避免深度复制复制所有节点的带来的性能损耗,immutable使用了结构共享,即如果对象树种的一个节点发生变化,只修改这个节点和受他影响的父节点,其他节点则共享。
在组件中使用:
import { shallowEqual, useDispatch, useSelector } from "react-redux";
import { getHotRecommendAction } from "../../store/actionCreators";
// redux hooks
const { hotRecommends } = useSelector(
(state) => ({
hotRecommends: state.getIn(["recommend", "hotRecommends"]),
}),
shallowEqual
);
const dispatch = useDispatch();
// other hooks
useEffect(() => {
dispatch(getHotRecommendAction(8));
}, [dispatch]);
useSelector 作用:共享状态,从Redux的store中提取数据(state)
const num=useSelector(state=>state.num)具体可以看看:www.5axxw.com/questions/c…