摘要:實現一個先不考慮中間件,實現一個簡潔的實現是最主要的一個了,通過可以創建一個用來存放應用中所有的,一個應用只能有一個。方法是用來把每一個用方法包裹一下,因為可能只是返回一個具有屬性的對象,只有用執行才有意義。正好可以利用的特性實現這個效果。
實現一個redux 先不考慮中間件,實現一個簡潔的redux 實現createStore
createStore是redux最主要的一個API了,通過createStore可以創建一個store用來存放應用中所有的state,一個應用只能有一個store。
// 先創建一個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; } // 默認執行reducer type類型不要命中reducer中自定義的case dispatch({type: "@ZQT-REDUX"}); return {getState, subscribe, dispatch} }
上面創建了一個redux.js文件,并暴露了一個createStore方法,接受reducer作為參數
// 創建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; // 為什么非要訂閱 因為沒一個connect實際上就是一個訂閱 每當dispatch執行的時候 就要重新執行以下update方法 store.subscribe(() => this.update()); this.update(); } update = () => { const {store} = this.context; const stateProps = mapStateToProps(store.getState()); // 每一個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)) }
上面創建了mini-react-redux.js文件,主要暴露了connect方法和Provider組件。
先看Provider組件。Provider利用的react的context屬性,把store注入到Provider組件,并返回this.props.children(也就是Provider組件里面嵌入的組件,一般是頁面的跟組件App組件),這樣所有的組件都可以共享store。
然后再看connect方法。connect方法是一個雙重嵌套的方法(專業名詞叫函數柯里化)里面的方法接受一個組件并且返回一個組件,正式高階組件的用法,外面的函數接受mapStateToProps和mapDispatchToProps兩個參數,mapStateToProps是用來把store里面的數據映射到組件的props屬性中,mapDispatchToProps是把用戶自己定義的action映射到組件的props屬性中。
在componentDidMount方法里面執行了store.subscribe(() => this.update())這句代碼,是因為每次使用dispatch觸發一個action的時候都要執行一下update方法,即重新獲取store數據并映射到組件中去,這樣才能保證store數據發生變化,組件props能同時跟著變化。
bindActionCreators方法是用來把每一個action用dispatch方法包裹一下,因為action可能只是返回一個具有type屬性的對象,只有用dispatch執行action才有意義。
到此為止,一個沒有中間件的不支持異步dispatch的簡潔版的redux已經實現了,創建一個demo,就可以看到效果了
// 創建index.js 作為項目入口文件,大家可以自己添加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實現), document.getElementById("root"))
上面實現了簡潔版的redux,再此基礎上添加支持中間件的代碼
// 修改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 給 第三方中間價使用 const midApi = { getState: store.getState, dispatch: (...args) => dispatch(...args) } // 創造第三方中間件使用 middlewareAPI 后返回的函數組成的數組 const middlewareChain = middlewares.map(middleware => middleware(midApi)) // 結合這一組函數 和 dispatch 組成的新的 dispatch,然后這個暴漏給用戶使用,而原有的 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方法修改了一下,多接受了一個enhancer方法,enhancer就是在index.js創建store的時候傳過來的applyMiddleware方法。判斷是否傳了enhancer參數,如果有就return enhancer(createStore)(reducer)
applyMiddleware方法接受多個中間件作為參數,這個方法的最終目的就是創建一個新的dispatch屬性,新的dispatch屬性是經過中間件修飾過的,并且暴露這個新的dispatch屬性,原來的dispatch屬性不變。
compose方法是一個可以吧compose(fn1,fn2,fn3)(arg)轉為fn3(fn2(fn1(arg)))的方法,也就是fn1的執行結果作為fn2的參數,fn2的執行結果作為fn1的參數,依次類推。正好可以利用reduce的特性實現這個效果。
const thunk = ({getState, dispatch}) => next => action => { // 如果是函數 就執行action if(typeof action === "function") { return action(dispatch, getState) } return next(action) } export default thunk
異步action在定義的時候返回的就是一個接受一個dispatch的方法,所以如果action是一個函數,就吧dispatch和getState方法傳給該action,并且執行該action。如果不是一個函數,就直接返回action。
到此為止一個支持中間件的redux就實現了,該demo只是為了學習redux的思想,不能作為真正的redux來使用,有很多類型檢查代碼都省略了
從實現迷你版的redux可以體會到redux精巧的設計和函數式編程的魅力,有隊函數式編程感興趣的可以看一下這篇文章https://llh911001.gitbooks.io...
github源碼地址:https://github.com/zhuqitao/z...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/109188.html
摘要:市面上竟然擁有多個虛擬庫。虛擬庫,就是出來后的一種新式庫,以虛擬與算法為核心,屏蔽操作,操作數據即操作視圖。及其他虛擬庫已經將虛擬的生成交由與處理了,因此不同點是,虛擬的結構與算法。因此虛擬庫是分為兩大派系算法派與擬態派。 去哪兒網迷你React是年初立項的新作品,在這前,去哪兒網已經深耕多年,擁有QRN(react-native的公司制定版),HY(基于React的hybird方案)...
摘要:前言目前最新版本是所以本文分析也基于這個版本。源碼分析直接切入主題由于目前是一個獨立的路由和中間件框架。所以分析的方向也以這兩個為主。源碼去年的時候有分析過現在對比分析思考下。 前言 目前express最新版本是4.16.2,所以本文分析也基于這個版本。目前從npm倉庫上來看express使用量挺高的,express月下載量約為koa的40倍。所以目前研究下express還是有一定意義...
摘要:本周在支持機票的項目中對做了大量改進,包括性能上與結構上的改進。但通過一些簡化改改良,代碼的可靠性大大提高了。此外,還有周邊的優化在目錄下提供一個,用于在舊式中替換。改善,里面內置了一個補丁,也是用于改善性能,或中的性能好差。 本周在支持機票的項目中對anujs做了大量改進,包括性能上與結構上的改進。與1.1.3一樣,還是差一個組件就完全兼容阿里的antd UI庫。 框架本身的改進有:...
摘要:原文地址的主要集中在函數返回值中,以下這個迷你的只簡單實現方法,如下測試代碼運行結果 原文地址:https://github.com/huruji/blog/issues/1 redux的主要API集中在createStore函數返回值中,以下這個迷你的redux只簡單實現createStore、dispatch、subscribe、getState方法,如下: const creat...
摘要:的中間件主要是通過模塊實現的。返回的也是一個對象這個其實就是,各個中間件的最底層第三層的哪個函數組成的圓環函數構成的這就是對源碼的一個整體解讀,水平有限,歡迎拍磚。后續的源碼解讀和測試例子可以關注源碼解讀倉庫 applyMiddleware源碼解析 中間件機制在redux中是強大且便捷的,利用redux的中間件我們能夠實現日志記錄,異步調用等多種十分實用的功能。redux的中間件主要是...
閱讀 3166·2021-11-23 09:51
閱讀 678·2021-10-14 09:43
閱讀 3200·2021-09-06 15:00
閱讀 2403·2019-08-30 15:54
閱讀 2557·2019-08-30 13:58
閱讀 1840·2019-08-29 13:18
閱讀 1372·2019-08-27 10:58
閱讀 506·2019-08-27 10:53