摘要:實(shí)現(xiàn)一個(gè)先不考慮中間件,實(shí)現(xiàn)一個(gè)簡潔的實(shí)現(xiàn)是最主要的一個(gè)了,通過可以創(chuàng)建一個(gè)用來存放應(yīng)用中所有的,一個(gè)應(yīng)用只能有一個(gè)。方法是用來把每一個(gè)用方法包裹一下,因?yàn)榭赡苤皇欠祷匾粋€(gè)具有屬性的對象,只有用執(zhí)行才有意義。正好可以利用的特性實(shí)現(xiàn)這個(gè)效果。
實(shí)現(xiàn)一個(gè)redux 先不考慮中間件,實(shí)現(xiàn)一個(gè)簡潔的redux 實(shí)現(xiàn)createStore
createStore是redux最主要的一個(gè)API了,通過createStore可以創(chuàng)建一個(gè)store用來存放應(yīng)用中所有的state,一個(gè)應(yīng)用只能有一個(gè)store。
// 先創(chuàng)建一個(gè)mini-redux.js文件: export function createStore(reducer) { // 初始化store let currentStore = {}; // 初始化事件列表 let currentListeners = []; // 獲取state function getState() { return currentStore; } // 訂閱事件 function subscribe(listener) { currentListeners.push(listener); } // 定義dispatch方法 function dispatch(action) { currentStore = reducer(currentStore, action); currentListeners.forEach(v => v()); // return dispatch; } // 默認(rèn)執(zhí)行reducer type類型不要命中reducer中自定義的case dispatch({type: "@ZQT-REDUX"}); return {getState, subscribe, dispatch} }
上面創(chuàng)建了一個(gè)redux.js文件,并暴露了一個(gè)createStore方法,接受reducer作為參數(shù)
// 創(chuàng)建mini-react-redux.js import React from "react"; import PropTypes from "prop-types"; export const connect = (mapStateToProps = state => state, mapDispatchToProps = {}) => (WrapComponent) => { return class connentComponent extends React.Component{ static contextTypes = { store: PropTypes.object } constructor(props, context) { super(props, context); this.state = { props: {} } } componentDidMount() { const {store} = this.context; // 為什么非要訂閱 因?yàn)闆]一個(gè)connect實(shí)際上就是一個(gè)訂閱 每當(dāng)dispatch執(zhí)行的時(shí)候 就要重新執(zhí)行以下update方法 store.subscribe(() => this.update()); this.update(); } update = () => { const {store} = this.context; const stateProps = mapStateToProps(store.getState()); // 每一個(gè)action需要用dispatch包裹一下 const stateDispatch = bindActionCreators(mapDispatchToProps, store.dispatch); this.setState({ props: { ...this.props, ...stateProps, ...stateDispatch } }) } render() { return} } } export class Provider extends React.Component{ static childContextTypes = { store: PropTypes.object } getChildContext() { return { store: this.store } } constructor(props, context) { super(props, context); this.store = props.store; } render() { return this.props.children } } function bindActionCreators(creators, dispatch) { const bound = {}; Object.keys(creators).forEach(v => { bound[v] = bindActionCreator(creators[v], dispatch); }) return bound; } function bindActionCreator(creator, dispatch) { return (...args) => dispatch(creator(...args)) }
上面創(chuàng)建了mini-react-redux.js文件,主要暴露了connect方法和Provider組件。
先看Provider組件。Provider利用的react的context屬性,把store注入到Provider組件,并返回this.props.children(也就是Provider組件里面嵌入的組件,一般是頁面的跟組件App組件),這樣所有的組件都可以共享store。
然后再看connect方法。connect方法是一個(gè)雙重嵌套的方法(專業(yè)名詞叫函數(shù)柯里化)里面的方法接受一個(gè)組件并且返回一個(gè)組件,正式高階組件的用法,外面的函數(shù)接受mapStateToProps和mapDispatchToProps兩個(gè)參數(shù),mapStateToProps是用來把store里面的數(shù)據(jù)映射到組件的props屬性中,mapDispatchToProps是把用戶自己定義的action映射到組件的props屬性中。
在componentDidMount方法里面執(zhí)行了store.subscribe(() => this.update())這句代碼,是因?yàn)槊看问褂胐ispatch觸發(fā)一個(gè)action的時(shí)候都要執(zhí)行一下update方法,即重新獲取store數(shù)據(jù)并映射到組件中去,這樣才能保證store數(shù)據(jù)發(fā)生變化,組件props能同時(shí)跟著變化。
bindActionCreators方法是用來把每一個(gè)action用dispatch方法包裹一下,因?yàn)閍ction可能只是返回一個(gè)具有type屬性的對象,只有用dispatch執(zhí)行action才有意義。
到此為止,一個(gè)沒有中間件的不支持異步dispatch的簡潔版的redux已經(jīng)實(shí)現(xiàn)了,創(chuàng)建一個(gè)demo,就可以看到效果了
// 創(chuàng)建index.js 作為項(xiàng)目入口文件,大家可以自己添加action和reducer,就可以查看效果 import React from "react"; import ReactDOM from "react-dom"; import { createStore, applyMiddleware } from "./mini-redux"; import { counter } from "./index.redux" import { Provider } from "./mini-react-redux"; import App from "./App" const store = createStore(counter); ReactDOM.render( (支持中間件和異步action的redux實(shí)現(xiàn)), document.getElementById("root"))
上面實(shí)現(xiàn)了簡潔版的redux,再此基礎(chǔ)上添加支持中間件的代碼
// 修改mini-redux.js為 export function createStore(reducer, enhancer) { if(enhancer) { return enhancer(createStore)(reducer) } let currentStore = {}; let currentListeners = []; function getState() { return currentStore; } function subscribe(listener) { currentListeners.push(listener); } function dispatch(action) { currentStore = reducer(currentStore, action); currentListeners.forEach(v => v()); // return dispatch; } dispatch({type: "@ZQT-REDUX"}); return {getState, subscribe, dispatch} } export function applyMiddleware(...middlewares) { return createStore=>(...args)=> { // 這里args 就是上面createStore 傳過來的reducers const store = createStore(...args) let dispatch = store.dispatch // 暴漏 getState 和 dispatch 給 第三方中間價(jià)使用 const midApi = { getState: store.getState, dispatch: (...args) => dispatch(...args) } // 創(chuàng)造第三方中間件使用 middlewareAPI 后返回的函數(shù)組成的數(shù)組 const middlewareChain = middlewares.map(middleware => middleware(midApi)) // 結(jié)合這一組函數(shù) 和 dispatch 組成的新的 dispatch,然后這個(gè)暴漏給用戶使用,而原有的 store.dispatch 是不變的,但是不暴漏 dispatch = compose(...middlewareChain)(store.dispatch); return{ ...store, dispatch } } } export function compose(...funcs) { if(funcs.length === 0){ return arg => arg } if(funcs.length === 1) { return funcs[0] } return funcs.reduce((ret, item) => (...args) => item(ret(...args))); }
createStore方法修改了一下,多接受了一個(gè)enhancer方法,enhancer就是在index.js創(chuàng)建store的時(shí)候傳過來的applyMiddleware方法。判斷是否傳了enhancer參數(shù),如果有就return enhancer(createStore)(reducer)
applyMiddleware方法接受多個(gè)中間件作為參數(shù),這個(gè)方法的最終目的就是創(chuàng)建一個(gè)新的dispatch屬性,新的dispatch屬性是經(jīng)過中間件修飾過的,并且暴露這個(gè)新的dispatch屬性,原來的dispatch屬性不變。
compose方法是一個(gè)可以吧compose(fn1,fn2,fn3)(arg)轉(zhuǎn)為fn3(fn2(fn1(arg)))的方法,也就是fn1的執(zhí)行結(jié)果作為fn2的參數(shù),fn2的執(zhí)行結(jié)果作為fn1的參數(shù),依次類推。正好可以利用reduce的特性實(shí)現(xiàn)這個(gè)效果。
const thunk = ({getState, dispatch}) => next => action => { // 如果是函數(shù) 就執(zhí)行action if(typeof action === "function") { return action(dispatch, getState) } return next(action) } export default thunk
異步action在定義的時(shí)候返回的就是一個(gè)接受一個(gè)dispatch的方法,所以如果action是一個(gè)函數(shù),就吧dispatch和getState方法傳給該action,并且執(zhí)行該action。如果不是一個(gè)函數(shù),就直接返回action。
到此為止一個(gè)支持中間件的redux就實(shí)現(xiàn)了,該demo只是為了學(xué)習(xí)redux的思想,不能作為真正的redux來使用,有很多類型檢查代碼都省略了
從實(shí)現(xiàn)迷你版的redux可以體會(huì)到redux精巧的設(shè)計(jì)和函數(shù)式編程的魅力,有隊(duì)函數(shù)式編程感興趣的可以看一下這篇文章https://llh911001.gitbooks.io...
github源碼地址:https://github.com/zhuqitao/z...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/109188.html
摘要:市面上竟然擁有多個(gè)虛擬庫。虛擬庫,就是出來后的一種新式庫,以虛擬與算法為核心,屏蔽操作,操作數(shù)據(jù)即操作視圖。及其他虛擬庫已經(jīng)將虛擬的生成交由與處理了,因此不同點(diǎn)是,虛擬的結(jié)構(gòu)與算法。因此虛擬庫是分為兩大派系算法派與擬態(tài)派。 去哪兒網(wǎng)迷你React是年初立項(xiàng)的新作品,在這前,去哪兒網(wǎng)已經(jīng)深耕多年,擁有QRN(react-native的公司制定版),HY(基于React的hybird方案)...
摘要:前言目前最新版本是所以本文分析也基于這個(gè)版本。源碼分析直接切入主題由于目前是一個(gè)獨(dú)立的路由和中間件框架。所以分析的方向也以這兩個(gè)為主。源碼去年的時(shí)候有分析過現(xiàn)在對比分析思考下。 前言 目前express最新版本是4.16.2,所以本文分析也基于這個(gè)版本。目前從npm倉庫上來看express使用量挺高的,express月下載量約為koa的40倍。所以目前研究下express還是有一定意義...
摘要:本周在支持機(jī)票的項(xiàng)目中對做了大量改進(jìn),包括性能上與結(jié)構(gòu)上的改進(jìn)。但通過一些簡化改改良,代碼的可靠性大大提高了。此外,還有周邊的優(yōu)化在目錄下提供一個(gè),用于在舊式中替換。改善,里面內(nèi)置了一個(gè)補(bǔ)丁,也是用于改善性能,或中的性能好差。 本周在支持機(jī)票的項(xiàng)目中對anujs做了大量改進(jìn),包括性能上與結(jié)構(gòu)上的改進(jìn)。與1.1.3一樣,還是差一個(gè)組件就完全兼容阿里的antd UI庫。 框架本身的改進(jìn)有:...
摘要:原文地址的主要集中在函數(shù)返回值中,以下這個(gè)迷你的只簡單實(shí)現(xiàn)方法,如下測試代碼運(yùn)行結(jié)果 原文地址:https://github.com/huruji/blog/issues/1 redux的主要API集中在createStore函數(shù)返回值中,以下這個(gè)迷你的redux只簡單實(shí)現(xiàn)createStore、dispatch、subscribe、getState方法,如下: const creat...
摘要:的中間件主要是通過模塊實(shí)現(xiàn)的。返回的也是一個(gè)對象這個(gè)其實(shí)就是,各個(gè)中間件的最底層第三層的哪個(gè)函數(shù)組成的圓環(huán)函數(shù)構(gòu)成的這就是對源碼的一個(gè)整體解讀,水平有限,歡迎拍磚。后續(xù)的源碼解讀和測試?yán)涌梢躁P(guān)注源碼解讀倉庫 applyMiddleware源碼解析 中間件機(jī)制在redux中是強(qiáng)大且便捷的,利用redux的中間件我們能夠?qū)崿F(xiàn)日志記錄,異步調(diào)用等多種十分實(shí)用的功能。redux的中間件主要是...
閱讀 3180·2021-11-23 09:51
閱讀 693·2021-10-14 09:43
閱讀 3218·2021-09-06 15:00
閱讀 2415·2019-08-30 15:54
閱讀 2571·2019-08-30 13:58
閱讀 1859·2019-08-29 13:18
閱讀 1387·2019-08-27 10:58
閱讀 525·2019-08-27 10:53