摘要:每個(gè)接受的和函數(shù)作為命名參數(shù),并返回一個(gè)函數(shù)。調(diào)用鏈中最后一個(gè)會(huì)接受真實(shí)的的方法作為參數(shù),并借此結(jié)束調(diào)用鏈。
簡介: 手寫實(shí)現(xiàn)redux基礎(chǔ)api
createStore( )和store相關(guān)方法api回顧:
createStore(reducer, [preloadedState], enhancer)
創(chuàng)建一個(gè) Redux store 來以存放應(yīng)用中所有的 state reducer (Function): 接收兩個(gè)參數(shù),當(dāng)前的 state 樹/要處理的 action,返回新的 state 樹 preloadedState: 初始時(shí)的 state enhancer (Function): store creator 的高階函數(shù),返回一個(gè)新的強(qiáng)化過的 store creator
Store 方法
getState() 返回應(yīng)用當(dāng)前的 state 樹 dispatch(action) 分發(fā) action。這是觸發(fā) state 變化的惟一途徑 subscribe(listener) 添加一個(gè)變化監(jiān)聽器。每當(dāng) dispatch action 的時(shí)候就會(huì)執(zhí)行,state 樹中的一部分可能已經(jīng)變化 replaceReducer(nextReducer) 替換 store 當(dāng)前用來計(jì)算 state 的 reducer(高級(jí)不常用,不作實(shí)現(xiàn))實(shí)現(xiàn) Redux 熱加載機(jī)制會(huì)用到
源碼實(shí)現(xiàn):
./self-redux.js export function createStore(reducer, enhancer) { if(enhancer) { return enhancer(createStore)(reducer) } let currentState = {} let currentListeners = [] function getState() { return currentState } function subscribe(listeners) { currentListeners.push(listener) } function dispatch(action) { currentState = reducer(currentState, action) currentListeners.forEach(v => v()) return action } dispatch({ type: "@rainie/init-store" }) return { getState, subscribe, dispatch } }
demo:驗(yàn)證正確性
// import { createStore } from "redux" // 將redux文件替換成自己實(shí)現(xiàn)的redux文件 import { createStore } from "./self-redux.js" // 這就是reducer處理函數(shù),參數(shù)是狀態(tài)和新的action function counter(state=0, action) { // let state = state||0 switch (action.type) { case "加機(jī)關(guān)槍": return state + 1 case "減機(jī)關(guān)槍": return state - 1 default: return 10 } } // 新建store const store = createStore(counter) const init = store.getState() console.log(`一開始有機(jī)槍${init}把`) function listener(){ const current = store.getState() console.log(`現(xiàn)在有機(jī)槍${current}把`) } // 訂閱,每次state修改,都會(huì)執(zhí)行l(wèi)istener store.subscribe(listener) // 提交狀態(tài)變更的申請(qǐng) store.dispatch({ type: "加機(jī)關(guān)槍" })combineReducers(reducers)
api簡介
把一個(gè)由多個(gè)不同 reducer 函數(shù)作為 value 的 object,合并成一個(gè)最終的 reducer 函數(shù) 實(shí)現(xiàn) Redux 熱加載機(jī)制會(huì)用到
import { combineReducers } from "redux" import todos from "./todos" import counter from "./counter" export default combineReducers({ todos, counter })
實(shí)現(xiàn):
實(shí)質(zhì)就是返回一個(gè)大的function 接受state,action,然后根據(jù)key用不同的reducer
注:combinedReducer的key跟state的key一樣
const reducer = combineReducers({ a: doSomethingWithA, b: processB, c: c }) function reducer(state = {}, action) { return { a: doSomethingWithA(state.a, action), b: processB(state.b, action), c: c(state.c, action) } }
function combindReducer(reducers) { // 第一個(gè)只是先過濾一遍 把非function的reducer過濾掉 const reducerKeys = Object.keys(reducers) const finalReducers = {} reducerKeys.forEach((key) => { if(typeof reducers[key] === "function") { finalReducers[key] = reducers[key] } }) const finalReducersKeys = Object.keys(finalReducers) // 第二步比較重要 就是將所有reducer合在一起 // 根據(jù)key調(diào)用每個(gè)reducer,將他們的值合并在一起 let hasChange = false; const nextState = {}; return function combind(state={}, action) { finalReducersKeys.forEach((key) => { const previousValue = state[key]; const nextValue = reducers[key](previousValue, action); nextState[key] = nextValue; hasChange = hasChange || previousValue !== nextValue }) return hasChange ? nextState : state; } }
applyMiddleware(...middleware)
使用包含自定義功能的 middleware 來擴(kuò)展 Redux 是 ...middleware (arguments): 遵循 Redux middleware API 的函數(shù)。 每個(gè) middleware 接受 Store 的 dispatch 和 getState 函數(shù)作為命名參數(shù),并返回一個(gè)函數(shù)。 該函數(shù)會(huì)被傳入 被稱為 next 的下一個(gè) middleware 的 dispatch 方法,并返回一個(gè)接收 action 的新函數(shù),這個(gè)函數(shù)可以直接調(diào)用 next(action),或者在其他需要的時(shí)刻調(diào)用,甚至根本不去調(diào)用它。 調(diào)用鏈中最后一個(gè) middleware 會(huì)接受真實(shí)的 store 的 dispatch 方法作為 next 參數(shù),并借此結(jié)束調(diào)用鏈。 所以,middleware 的函數(shù)簽名是 ({ getState, dispatch }) => next => action
import { createStore, combineReducers, applyMiddleware } from "redux" import thunk from "redux-thunk" import * as reducers from "./reducers" let reducer = combineReducers(reducers) // applyMiddleware 為 createStore 注入了 middleware: let store = createStore(reducer, applyMiddleware(thunk))中間件機(jī)制applyMiddleware的實(shí)現(xiàn)
中間件機(jī)制圖
實(shí)現(xiàn)步驟
1.擴(kuò)展createStore,使其接受第二個(gè)參數(shù)(中間件其實(shí)就是對(duì)createStore方法的一次擴(kuò)展)
2.實(shí)現(xiàn)applyMiddleware,對(duì)store的disptach進(jìn)行處理
3.實(shí)現(xiàn)一個(gè)中間件
正常調(diào)用
import React from "react" import ReactDOM from "react-dom" // import { createStore, applyMiddleware} from "redux" import { createStore, applyMiddleware} from "./self-redux" // import thunk from "redux-thunk" import thunk from "./self-redux-thunk" import { counter } from "./index.redux" import { Provider } from "./self-react-redux"; import App from "./App" const store = createStore(counter, applyMiddleware(thunk)) ReactDOM.render( (), document.getElementById("root"))
// 便于理解:函數(shù)柯利化例子 function add(x) { return function(y) { return x+y } } add(1)(2) //3
applymiddleware
// ehancer(createStore)(reducer) // createStore(counter, applyMiddleware(thunk)) // applyMiddleware(thunk)(createStore)(reducer) // 寫法函數(shù)柯利化 export function applyMiddleware(middleware) { return function (createStore) { return function(...args) { // ... } } } // 只處理一個(gè) middleware 時(shí) export function applyMiddleware(middleware) { return createStore => (...args) => { const store = createStore(...args) let dispatch = store.dispatch const midApi = { getState: store.getState, dispatch: (...args) => dispatch(...args) } // 經(jīng)過中間件處理,返回新的dispatch覆蓋舊的 dispatch = middleware(midApi)(store.dispatch) // 正常中間件調(diào)用:middleware(midApi)(store.dispatch)(action) return { ...store, dispatch } } } // 處理多個(gè)middleware時(shí) // 多個(gè) compose export function applyMiddleware(...middlewares) { return createStore => (...args) => { const store = createStore(...args) let dispatch = store.dispatch const midApi = { getState: store.getState, dispatch: (...args) => dispatch(...args) } const middlewareChain = middlewares.map(middleware => middleware(midApi)) dispatch => compose(...middlewareChain(store.dispatch)) // dispatch = middleware(midApi)(store.dispatch) // middleware(midApi)(store.dispatch)(action) return { ...store, dispatch } } }
手寫redux-thunk異步中間件實(shí)現(xiàn)
// middleware(midApi)(store.dispatch)(action) const thunk = ({ dispatch, getState }) => next => action => { // next就是store.dispatch函數(shù) // 如果是函數(shù),執(zhí)行以下,參數(shù)dispatch和getState if (typeof action == "function") { return action(dispatch, getState) } // 默認(rèn) 什么都不干 return next(action) } export default thunk 處理異步action export function addGunAsync() { // thunk插件作用,這里可以返回函數(shù) return dispatch => { setTimeout(() => { // 異步結(jié)束后,手動(dòng)執(zhí)行dispatch dispatch(addGun()) }, 2000) } }
趁熱打鐵,再實(shí)現(xiàn)一個(gè)中間件: dispatch接受一個(gè)數(shù)組,一次處理多個(gè)action
export arrayThunk = ({ dispatch, getState }) => next => action => { if(Array.isArray(action)) { return action.forEach(v => dispatch(v)) } return next(action) } 這類action會(huì)被處理 export function addTimes() { return [{ type: ADD_GUN },{ type: ADD_GUN },{ type: ADD_GUN }] }bindActionCreators的實(shí)現(xiàn)
在react-redux connect mapDispatchToProps中使用到了該方法,可以去看那篇blog,有詳解~
api: bindActionCreators(actionCreators, dispatch)
把 action creators 轉(zhuǎn)成擁有同名 keys 的對(duì)象,但使用 dispatch 把每個(gè) action creator 包圍起來,這樣可以直接調(diào)用它們
實(shí)現(xiàn):
function bindActionCreator(creator, dispatch) { return (...args) => dispatch(creator(...args)) } export function bindActionCreators(creators, dispatch) { let bound = {} Object.keys(creators).forEach( v => { let creator = creators[v] bound[v] = bindActionCreator(creator, dispatch) }) return bound } // 簡寫 export function bindActionCreators(creators, dispatch) { return Object.keys(creators).reduce((ret, item) => { ret[item] = bindActionCreator(creators[item], dispatch) return ret }, {}) }compose的實(shí)現(xiàn)
api: compose(...functions)
從右到左來組合多個(gè)函數(shù)。 當(dāng)需要把多個(gè) store 增強(qiáng)器 依次執(zhí)行的時(shí)候,需要用到它
import { createStore, applyMiddleware, compose } from "redux" import thunk from "redux-thunk" import DevTools from "./containers/DevTools" import reducer from "../reducers" const store = createStore( reducer, compose( applyMiddleware(thunk), DevTools.instrument() ) )
實(shí)現(xiàn):
compose(fn1, fn2, fn3)
fn1(fn2(fn3))
export function compose(...funcs) { if(funcs.length == 0) { return arg => arg } if(funcs.length == 1) { return funcs[0] } return funcs.reduce((ret,item) => (...args) => ret(item(...args))) }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/98479.html
簡介:簡單實(shí)現(xiàn)react-redux基礎(chǔ)api react-redux api回顧 把store放在context里,所有子組件可以直接拿到store數(shù)據(jù) 使組件層級(jí)中的 connect() 方法都能夠獲得 Redux store 根組件應(yīng)該嵌套在 中 ReactDOM.render( , rootEl ) ReactDOM.render( ...
摘要:前端進(jìn)階進(jìn)階構(gòu)建項(xiàng)目一配置最佳實(shí)踐狀態(tài)管理之痛點(diǎn)分析與改良開發(fā)中所謂狀態(tài)淺析從時(shí)間旅行的烏托邦,看狀態(tài)管理的設(shè)計(jì)誤區(qū)使用更好地處理數(shù)據(jù)愛彼迎房源詳情頁中的性能優(yōu)化從零開始,在中構(gòu)建時(shí)間旅行式調(diào)試用輕松管理復(fù)雜狀態(tài)如何把業(yè)務(wù)邏輯這個(gè)故事講好和 前端進(jìn)階 webpack webpack進(jìn)階構(gòu)建項(xiàng)目(一) Webpack 4 配置最佳實(shí)踐 react Redux狀態(tài)管理之痛點(diǎn)、分析與...
摘要:課程制作和案例制作都經(jīng)過精心編排。對(duì)于開發(fā)者意義重大,希望對(duì)有需要的開發(fā)者有所幫助。是從提案轉(zhuǎn)為正式加入的新特性。并不需要用繼承,而是推薦用嵌套。大型項(xiàng)目中模塊化與功能解耦困難。從而更加易于復(fù)用和獨(dú)立測試。但使用會(huì)減少這種幾率。 showImg(https://segmentfault.com/img/bVbpNRZ?w=1920&h=1080); 講師簡介 曾任職中軟軍隊(duì)事業(yè)部,參與...
摘要:面試的公司分別是阿里網(wǎng)易滴滴今日頭條有贊挖財(cái)滬江餓了么攜程喜馬拉雅兌吧微醫(yī)寺庫寶寶樹海康威視蘑菇街酷家樂百分點(diǎn)和海風(fēng)教育。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本人于7-8月開始準(zhǔn)備面試,過五關(guān)斬六將,最終抱得網(wǎng)易歸,深深感受到高級(jí)前端面試的套路。以下是自己整理的面試題匯總,不敢藏私,統(tǒng)統(tǒng)貢獻(xiàn)出來。 面試的公司分...
閱讀 1295·2021-10-08 10:04
閱讀 1922·2021-09-04 16:40
閱讀 2536·2019-08-30 13:21
閱讀 2280·2019-08-29 15:10
閱讀 2848·2019-08-29 12:35
閱讀 1189·2019-08-26 17:41
閱讀 3062·2019-08-26 17:03
閱讀 1136·2019-08-26 12:01