Redux作为react的状态管理器,从组件中把状态抽离出来,统一封装到Redux,实现了UI与逻辑耦合分离。Redux的实现理念,有很多值得我们的学习,例如函数的柯林化,洋葱模型,以及数组方法reduce的巧用。
只有明白了Redux的设计理念,不论经过多长时间,都能手写出一个Redux,同样的,可以把其可借鉴的点运用到平时写的代码当中。
- 初始化一个Redux。
function CreateStore() {
let state;
function dispatch() {
}
function getState() {
}
function subscrible() {
}
return {
dispatch,
getState,
subscrible
}
}
- 丰富各项功能。
function CreateStore(reducer) {
let state;
let listener = [];
// 发起action,触发reducer
function dispatch(action) {
// 通过action去匹配reducer中对应的操作,并且返回state
state = reducer(state, action)
return action;
}
// 初始化reducer,返回默认state
dispatch({ type: 'init'})
function getState() {
return state;
}
function subscrible(listner) {
listener.push(listner);
}
return {
dispatch,
getState,
subscrible
}
}
至此,一个最最简单的redux就完成了,接下来,我们看一看在实现一个reducer上需要有哪些注意点。
// 初始化一个reducer时,需要给一个默认值
// reducer 必须是一个纯函数
function countReducer(state={ num: 0 }, action) {
let { type } = action;
switch (type) {
case 'add':
return {
...state,
num: ++state.num
}
case 'subtract':
return {
...state,
num: --state.num
}
default :
return {
...state,
}
}
}
接着我们把countReducer传入到CreateStore当中进行使用。
const store = new CreateStore(countReducer);
store.dispatch({
type: 'add'
})
store.getState() // { num: 1 }
store.dispatch({
type: 'subtract'
})
store.getState() // { num: 0 }
- 实现combineReducers。 在实际业务需求中,reducers当然不止一个,但是CreateStore中第一个参数只能接受一个函数。那就需要把多个reducers合并成一个大的reducer,接下来实现combineReducers。
function combineReducers(reducers) {
const reducersKey = object.keys(reducers);
return (state = {}, action) => {
let nextState = {};
reducersKey.forEach(key => {
nextState[key] = reducers[key](state[key], action);
})
return nextState;
}
}
还可以这样写
function combineReducers(reducers) {
const reducersKey = Object.keys(reducers);
return (state = {}, action) => {
return reducersKey.reduce((prev, curr) => {
prev[curr] = reducers[curr](state[curr], action);
return prev;
}, {})
}
}
combineReducers把单个单个的reducer合成了一颗大树,每当发起action时,从顶部向下执行到每个reducer,也就是说,当我发起一个type为add action时,counterReducer中的type会被匹配,其他的子reducer也会跟着执行,只不过这些reducer中没有匹配的type,返回默认的state。
再实现一个reducer
function ageModifyReducer(state={ name: 'Joe', age: 18 }, action) {
let { type } = action;
switch (type) {
case 'name':
return {
...state,
name: action.name
}
case 'age':
return {
...state,
age: action.age
}
default :
return {
...state,
}
}
}
let reducer = combineReducers({
ageModifyReducer,
countReducer
})
let store = CreateStore(reducer);
store.getState(); // { ageModifyReducer: { name: "Joe", age: 18 }, countReducer: { num: 0 }}
// 接下来修改年龄
store.dispatch({
type: 'name',
name: 'Mike'
})
store.getState(); // { ageModifyReducer: { name: "Mike", age: 18 }, countReducer: { num: 0 }}
到这一步,能进行状态管理的redux就算完成了,接下来,解析中间件,中间件这里,刚开始时我是傻傻的,后来时隔一段时间再回去细细品味,还是恶心🤢,但是现在大概能掌握了其实现的理念。
- 我们先从creatStore改造入手
function CreateStore(reducer, initialState, enhancer) {
let state;
let listener = [];
// 如果传进来的第二个参数是中间件,内部需要做处理,把中间件给到enhancer
if (initialState && typeof initialState === 'function') {
enhancer = initialState;
initialState = undefined;
}
// 如果传入了中间件 ,那么重新构造一个store, 并且以下逻辑不走
if(enhancer && typeof enhancer === 'function') {
return enhancer(CreateStore)(reducer, initialState);
}
// 以下逻辑不走了
// 发起action,触发reducer
function dispatch(action) {
// 通过action去匹配reducer中对应的操作,并且返回state
state = reducer(state, action)
return action;
}
// 初始化reducer,返回默认state
dispatch({ type: 'init'})
function getState() {
return state;
}
function subscrible(listner) {
listener.push(listner);
}
return {
dispatch,
getState,
subscrible
}
}
- 然后实现一个applyMiddlewares
// 首先CreateStore中,我们看见当我们执行applyMiddlewares需要传两次参数
if(enhancer && typeof enhancer === 'function') {
return enhancer(CreateStore)(reducer, initialState);
}
function applyMiddlewares(...middlerWares) {
return (store) => (reducer, initialState) {
const store = store(reducer, initialState);
// 这里其实在中间件中,用户手动dipatch一个action,是会报错的
let dispatch = () => {
throw Error('不能在此执行dispatch')
}
const middleAPI = {
getState: store.getState,
dispatch : (...agrs) => dispatch(...agrs)
}
const chain = middlerWares.map(middleWare => middleWare(middleAPI));
dispath = compose(...chain)(store.dispatch);
return {
...store,
dispatch
}
}
}
通过applyMiddlewares返回的dispatch函数,不是真正意义上的dispatch函数,因为在Redux中,发起dispatch之后就会立即执行reducer。但在这里不是,真正触发dispatch函数的是最里层的中间件。所以在组合中间件过程中还需要注意顺序,接着来剖析中间件。 假设我们现在有一个中间件logger。连续使用两次
function logger() {
return (next) => (action) => {
let returnValue = next(action);
return returnValue;
}
}
applyMiddlewares(logger, logger);
// 看看 applyMiddlewares之后返回的dispatch长什么样
disaptch = (action) => {
// returnValue就是action
let returnValue = ((action) => {
let returnValue = store.dispatch(action);
return returnValue;
})(action);
returnValue;
}
当我们在外部发起store.dispatch()时候,就是执行上面的dispatch函数,层层向里执行,然后有层层向外执行,所谓的洋葱模型。
以上就是我对Redux的学习结果,欢迎大家阅读,如有不对地方,请联系我指出,感谢各位的观看。