miniRedux實(shí)現(xiàn)與源碼解讀

本文主要介紹redux的react-redux的原理

redux原理

github地址:https://github.com/majunchang/miniRedux

總體流程圖7揽4缥濉茶没!

原生react的調(diào)用和常用方法

react流程圖展示

image
  • redux中有一個(gè)reducer函數(shù)和action 通過(guò)dispatch(action)來(lái)觸發(fā)reducer的對(duì)應(yīng)的case
  • 提供一個(gè)createStore方法 傳入reducer 返回的對(duì)象中包含getState和subscribe和dispatch方法

調(diào)用示例:

redux 原生版的調(diào)用 getState()獲取狀態(tài) subscribe()進(jìn)行監(jiān)聽(tīng) dispatch()觸發(fā)相應(yīng)的action 改變state

import { createStore } from './woniuRedux/woniuRedux'

// 這就是reducer處理函數(shù)坦报,參數(shù)是狀態(tài)和新的action
export  function counter (state = 0, action) {
  // let state = state||0
  console.log(action)
  console.log(state)
  switch (action.type) {
    case '加蘋(píng)果':
      return state + 1
    case '吃蘋(píng)果':
      return state - 1
    default:
      return 10
  }
}

const store = createStore(counter)
// console.log
const init = store.getState()
console.log(`一開(kāi)始有${init}個(gè)蘋(píng)果`)
function listener () {
  const current = store.getState()
  console.log(`現(xiàn)在有${current}個(gè)蘋(píng)果`)
}
// 訂閱,每次state修改稚失,都會(huì)執(zhí)行l(wèi)istener
store.subscribe(listener)
// 提交狀態(tài)變更的申請(qǐng)
store.dispatch({ type: '加蘋(píng)果' })
store.dispatch({ type: '加蘋(píng)果' })
store.dispatch({ type: '加蘋(píng)果' })
store.dispatch({ type: '吃蘋(píng)果' })
store.dispatch({ type: '吃蘋(píng)果' })

redux實(shí)現(xiàn)原理(源碼解析)(簡(jiǎn)易版)

主要介紹createStore applyMiddleware和bindActionCreators

caeateStore 源碼解讀

export function createStore (reducer, enhancer) {
  if (enhancer) {
    console.log('enhancer', enhancer)      ①
    return enhancer(createStore)(reducer)

    //  return applymiddleware(thunk)(createStore)(reducer)
  }
  let currentState = {}
  let currentListeners = []

  function getState () {
    return currentState
  }

  function subscribe (listener) {
    currentListeners.push(listener)
  }

  function dispatch (action) {
    currentState = reducer(currentState, action)
    currentListeners.forEach(v => {
      v()
    })
    return action
  }

  //  初次調(diào)用的時(shí)候 首先執(zhí)行一次 dispatch
  dispatch({type: '@@redux/firstTime'})

  return {getState, subscribe, dispatch}
}
  1. createStore 內(nèi)部是一個(gè)觀察者模式鸣皂, subscribe 添加注冊(cè)函數(shù) dispatch讓函數(shù)自調(diào)用
  2. 首次調(diào)用createStore的時(shí)候 內(nèi)部會(huì)執(zhí)行一次dispatch 將reducer綁定進(jìn)來(lái)
  3. enhancer 是一個(gè)組合 store creator 的高階函數(shù),返回一個(gè)新的強(qiáng)化過(guò)的 store creator瞻坝。這與 middleware 相似,它也允許你通過(guò)復(fù)合函數(shù)改變 store 接口杏瞻。
enhancer ? (createStore) {
    return function () {
      var _console, _console2;

      for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
        args[_key2] = argum…

普及一下高階函數(shù)

高階組件就是一個(gè)函數(shù)所刀,且該函數(shù)接受一個(gè)組件作為參數(shù),并返回一個(gè)新的組件

// 高階組件 思想
function hello() {
    console.log('我喜歡react');
}

function WrapperHello(fn) {
    return function () {
        console.log('before hello');
        fn()
        console.log('after hello');
    }
}

var hello = WrapperHello(hello);
hello()

 屬性代理
class Hello extends React.Component {
    render() {
        return <h2>高階組件的參數(shù)組件</h2>
    }
}

function wrapperHello(Comp) {
    class WrapComp extends React.Component {
        render() {
            return (<div>
                <p>這是hoc高階組件特有的元素</p>
                <Comp  {...this.props}></Comp>
            </div>)
        }
    }
    return WrapComp
}
 反向繼承
function wrapperHello(Comp) {
    class WrapComp extends Comp{
        componentDidMount(){
            console.log('高階組件新增的生命周期捞挥,加載完成');
        }
        render(){
            return <Comp></Comp>
        }
    }
    return WrapComp
}


Hello = wrapperHello(Hello);

applyMiddleware源碼解讀

//  中間件機(jī)制
export function applyMiddleware (...middlewares) {
  
  return createStore => (...args) => {
    console.log(args)
    //  這里的...args指的是解耦之后的renducer   在這里 指的就是counter 
    console.log(...args)  
    const store = createStore(...args)
    let dispatch = store.dispatch
    let midApi = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args)
    }
    //  單個(gè)中間件的情況
    // dispatch = middleware(midApi)(store.dispatch)
    // dispatch = middware(midApi)(stroe.dispatch)(action)
    // 多個(gè)中間件的情況
    console.log(store) //  =>  store 就是一個(gè)對(duì)象  里面包含dispatch getState和subscribe等方法
    console.log('middles', middlewares)
    let middlewareChain = middlewares.map(middleware => middleware(midApi))
       //  返回的這個(gè)dispatch  就執(zhí)行過(guò)了所有的中間件  帶有了中間件的功能
    dispatch = compose(...middlewareChain)(store.dispatch)
    return {
      ...store,
      dispatch
    }
  }
}

compose函數(shù)源碼

function compose (...fns) {
  if (fns.length === 0) {
    return args => args
  }
  if (fns.length === 1) {
    return fns[0]
  }
  // return fns.reduce((ret, item) => (...args) => ret(item(...args)))
  return fns.reduce((ret, item) => (...args) => {
    console.log('當(dāng)有多個(gè)參數(shù)的時(shí)候')
    //  ...args ==>> store.dispatch的這個(gè)方法  item和ret指代不同的中間件
    /*
    //假設(shè) 
    middleChain = [a,b,c]
    dispatch = compose(...middlewareChain)(store.dispatch) = compose(a,b,c)(store.dispatch)
    // 那么這個(gè)函數(shù)在compose中 就被拆解為
    dispatch = compose(a(b(c)))(store.dispatch)
    */
    return ret(item(...args))
  })
}

結(jié)合中間件的源碼來(lái)看 我們這里以thunk舉例

  • thunk中最開(kāi)始接受的參數(shù) {dispatch getState} 是從midApi中傳來(lái)的
  • next 指代store.dispatch action就是action
const thunk = ({dispatch, getState}) => next => action => {
  if (typeof action === 'function') {
    //  如上面所示
    return action(dispatch, getState)
  }
  //  默認(rèn)情況下
  return next(action)
}

export default thunk

bindActionCreators 源碼解讀

官網(wǎng)用法 : http://www.redux.org.cn/docs/api/bindActionCreators.html

//  工具函數(shù)  這個(gè)函數(shù)的作用是為了讓creator函數(shù)里面的參數(shù)進(jìn)行透?jìng)?/*
    addGun(參數(shù))
    dispatch(addGun(參數(shù)))
 */
function bindActionCreator (creator, dispatch) {
  return (...args) => dispatch(creator(...args))
}

//  bindActionCreators
//   {addGun, removeGun, addGunAsync}  就是形式參數(shù) creators
export function bindActionCreators (creators, dispatch) {
  let bound = {}
  Object.keys(creators).forEach((fnKey, index) => {
    let creator = creators[fnKey]
    bound[fnKey] = bindActionCreator(creator, dispatch)
  })
  return bound
  /*
    還可以采用另外一種寫(xiě)法
     return Object.keys(creators).reduce((ret,item)=>{
       ret[item] = bindActionCreator(creators[item],dispatch)
        return ret
    },{})
     */
}

mini-react-redux的實(shí)現(xiàn)原理和源碼解讀

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末浮创,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子砌函,更是在濱河造成了極大的恐慌斩披,老刑警劉巖溜族,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異垦沉,居然都是意外死亡煌抒,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)厕倍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)寡壮,“玉大人,你說(shuō)我怎么就攤上這事讹弯】黾龋” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵组民,是天一觀的道長(zhǎng)棒仍。 經(jīng)常有香客問(wèn)我,道長(zhǎng)臭胜,這世上最難降的妖魔是什么降狠? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮庇楞,結(jié)果婚禮上榜配,老公的妹妹穿的比我還像新娘。我一直安慰自己吕晌,他們只是感情好蛋褥,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著睛驳,像睡著了一般烙心。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上乏沸,一...
    開(kāi)封第一講書(shū)人閱讀 49,829評(píng)論 1 290
  • 那天淫茵,我揣著相機(jī)與錄音,去河邊找鬼蹬跃。 笑死匙瘪,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蝶缀。 我是一名探鬼主播丹喻,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼翁都!你這毒婦竟也來(lái)了碍论?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤柄慰,失蹤者是張志新(化名)和其女友劉穎鳍悠,沒(méi)想到半個(gè)月后税娜,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡藏研,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年巧涧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片遥倦。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡谤绳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出袒哥,到底是詐尸還是另有隱情缩筛,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布堡称,位于F島的核電站瞎抛,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏却紧。R本人自食惡果不足惜桐臊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望晓殊。 院中可真熱鬧断凶,春花似錦、人聲如沸巫俺。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)介汹。三九已至却嗡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嘹承,已是汗流浹背窗价。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留叹卷,地道東北人撼港。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像豪娜,于是被迫代替她去往敵國(guó)和親餐胀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容