从源码到实践理解redux
本文会先从源码分析如何实现redux,然后通过一个购物车案例来实践。
原理
在分析redux源码,先了解一种订阅模式,这对后面的理解是有帮助的,如图所示:
redux源码分析
为了更好的理解,这里采用了类来实现(redux源码是函数闭包实现)
class store {
constructor(combinedReducer, initState){
this.state = initState; //状态树
this.listeners = []; //订阅表(订阅者列表)
this.combinedReducer = combinedReducer; //状态改变方法
}
// 获取状态树
getState = ()=>{
return this.state
}
// 发布(触发事件)
dispatch = (action)=>{
//修改状态
//根据action.type找到修改的位置,根据action.payload的值修改原状态的值
this.state = combinedReducer(this.state,action)
//通知订阅者
//执行每个订阅者的监听函数
listeners.forEach((fn) => fn())
}
// 订阅(绑定事件)
subscribe = (listener)=>{
this.listeners.push(listener)
}
}
/**
* 功能:创建并返回一个store对象
*/
const createStore = (combinedReducer,initState)=>{
return new store(combinedReducer,initState)
}
/**
* 功能:组装多个reducer函数,返回一个改变状态的纯函数
*/
combineReducers = (reducers)=>{
return function(state={},action={}){
for(let reducer of reducers){
newState[reducer] = reducer(state[reducer],action)
}
return newState
}
}
// 对外提供两个方法
export {createStore,combineReducers}
购物车案例
carPage : 购物车页面; starPage : 收藏夹页面; productPage : 商品详情页面
功能:加入购物车;收藏商品;
代码:
/*------------------------使用---------------------------------*/
import { combineReducers,createStore } from "./store"
// 1.自定义的reducer
const carPageReducer = (state, action) =>{
switch(action.type){
case ADD_TO_CAR:
return {...state,totalNum:state.totalNum+1}
}
}
const starPageReducer = (state, action) =>{
switch(action.type){
case STAR_PRODUCT:
const newStars = [...stars,action.payload.productId]
return {...state, stars:newStars}
}
}
// 2.组装reducer,创建store
const initState = {
//购物车页面的状态
carPageReducer:{
totalNum:0
},
//收藏页面的状态
starPageReducer:{
stars:['商品X','商品Y'],
}
}
const combinedReducer = combineReducers([carPageReducer,starPageReducer])
const store = createStore(combinedReducer,initState)
// 3.订阅
// 在页面carPage中
subscribe(()=>{
document.querySelector('#totalNum').innerHTML = store.getState().carPageReducer.totalNum;
})
// 在页面starPage中
subscribe(()=>{
document.querySelector('#stars').innerHTML = createComponent(store.getState().starPageReducer.stars);
})
// 4.发布
// 在productPage页面中
const addToCarAction = {
type: "ADD_TO_CAR",
payload: {}
}
store.dispath(addToCarAction)
const starAction = {
type: "STAR_PRODUCT",
payload: {productId:'商品Z'}
}
store.dispath(starAction)
流程图: