国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

帶著問題看 react-redux 源碼實現

JellyBool / 2306人閱讀

摘要:更新類型及具體內容負責更新數據的具體邏輯。即根據當前及攜帶的信息合成新的數據。下面帶著這些問題深入了解本質上也是高階組件的一種實現。核心實現聲明以被子組件獲取。通過的實現,我們可以得到的重要性淺比較的實現由此可以看到的重要性。

前言

Redux作為通用的狀態管理器,可以搭配任意界面框架。所以并搭配react使用的話就要借助redux官方提供的React綁定庫react-redux,以高效靈活的在react中使用redux。下面我們一起看看是react-redux如何靈活高效的

redux 概述

在開始之間還是大概提一下redux的內容,以免脫節。比較早的時候也解讀了下redux的源碼實現,可以參考一下

Redux 是 JavaScript 狀態容器,旨在提供可預測化的狀態管理。 其包括action、store、reducer等三部分:

在理解各部分作用之前,我們可以通過一個更新數據的例子來捋下思路:

    要更新數據,肯定有個數據庫來存儲和維護數據。即數據層。

    具體如何更新,需要有負責執行的部分,即邏輯處理層。

    具體何時更新哪個字段、何時更新,同樣需要分發層來控制。

根據上面的例子我們再對比下redux的流程圖(圖片來自阮一峰大佬): 可以對照著來理解不同部分的作用。

action

就如上面所說負責更新字段和更新時機。 用戶接觸到的是view(即用戶界面),對應的更新信息通過acton傳遞給reducer。

function addTodo(text) {
  return {
    // 更新類型及具體內容
    type: ADD_TODO,
    text
  }
}
reducer

負責更新數據的具體邏輯。
即根據當前state及action攜帶的信息合成新的數據。

function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      })
    // 不同更新類型的處理邏輯不同  
    case ADD_TODO:
      return Object.assign({}, state, {
        todos: [
          ...state.todos,
          {
            text: action.text,
            completed: false
          }
        ]
      })
    default:
      return state
  }
}
store

store就是負責維護和管理數據。 此外還有dispatch,subscrible等api來完成更新事件的分發。 例如:

import { createStore } from "redux"
import todoApp from "./reducers"
let store = createStore(todoApp)
import {
  addTodo} from "./actions"
// 注冊監聽事件
const unsubscribe = store.subscribe(() => console.log(store.getState()))
// 發起一系列 action
store.dispatch(addTodo("Learn about actions"))
// 停止監聽
unsubscribe()

到這里,我們應該就大概明白redux如何更新管理數據的了。

通過store.subscribe來監聽狀態更新,這是響應變化的重要一步。

然后通過stroe.getState()獲取相應數據

具體更新通過action和reducer來實現了。

那么對照react-redux的實例官方demo,來結合React的時候,會發現redux使用有些不同之處。

不同之處

大概可以有下面這三點:

    組件沒有顯示調用store.subscrible()

    state也不是通過Store.getState()來獲取。

    多了Provider和connect方法

可以猜測,上述差異是React-redux幫我們封裝了綁定監聽等過程,避免需要每個應用都重復相同的操作。使得React組件的數據源只關注props和state。

下面帶著這些問題深入了解React-redux.

react-redux

本質上 react-redux也是react高階組件HOC的一種實現。其基于 容器組件和展示組件相分離 的開發思想來實現的。 其核心是通過兩部分來實現: 1、Provider 2、container通過connect來解除手動調用store.subscrible

provider 的實現

provider用法如下,綁定之后,再經過connect處理,就可以在組件中通過props訪問對應信息了。

import React from "react"
import { render } from "react-dom"
import { Provider } from "react-redux"
import { createStore } from "redux"
import todoApp from "./reducers"
import App from "./components/App"

let store = createStore(todoApp)
render(
  // 綁定store
  
    <App />
  Provider>,
  document.getElementById("root")
)

在看源碼之前,我們先自行猜測一下。
前面也提到了Provider是React組件。
那么為了讓子組件都能方便的訪問到store,store這個屬性會如何傳遞呢。props?context?

核心實現

import { Component, Children } from "react"
export default class Provider extends Component {
  // 聲明context 以被子組件獲取。
  getChildContext() {
    return { store: this.store }
  }

  constructor(props, context) {
    super(props, context)
    // 掛載store到Provider
    this.store = props.store
  }

  render() {
    // 判斷是否只有一個child,是則返回該child節點,否則拋錯
    return Children.only(this.props.children)
  }
}

Provider將store傳遞給子組件,具體如何和組件綁定就是conect做的事情了。

connect

connect連接組件和store,該操作并不修改原組件而是返回一個新的增強了關聯store的組件。
根據這個描述,這顯然就是個React高階組件(HOC)嗎。先看一下使用:

connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])

接收四個參數,具體每個參數的作用詳細可以參考cn.redux.js.org/docs/react-…

[mapStateToProps(state, [ownProps]): stateProps] (Function): 如果定義該參數,組件將會監聽 Redux store 的變化。任何時候,只要 Redux store 發生改變,mapStateToProps 函數就會被調用。該回調函數必須返回一個純對象,這個對象會與組件的 props 合并。

[mapDispatchToProps(dispatch, [ownProps]): dispatchProps](Object or Function): 如果傳遞的是一個對象,那么每個定義在該對象的函數都將被當作 Redux action creator,對象所定義的方法名將作為屬性名;每個方法將返回一個新的函數,函數中dispatch方法會將 action creator 的返回值作為參數執行。這些屬性會被合并到組件的 props 中。

[mergeProps(stateProps, dispatchProps, ownProps): props] (Function): 如果指定了這個參數,mapStateToProps() 與 mapDispatchToProps() 的執行結果和組件自身的 props 將傳入到這個回調函數中。該回調函數返回的對象將作為 props 傳遞到被包裝的組件中。

[options] (Object) 如果指定這個參數,可以定制 connector 的行為

[pure = true] (Boolean): 如果為 true,connector 將執行 shouldComponentUpdate 并且淺對比 mergeProps 的結果,避免不必要的更新,默認true

[withRef = false] (Boolean): 如果為 true,connector 會保存一個對被被包含的組件實例的引用,該引用通過 getWrappedInstance() 方法獲得。默認false

結合下面的例子能更清晰知道作用是什么。

import { connect } from "react-redux"
import { toggleTodo } from "../actions"
import TodoList from "../components/TodoList"
import { VisibilityFilters } from "../actions"

const getVisibleTodos = (todos, filter) => {
  switch (filter) {
    case VisibilityFilters.SHOW_ALL:
      return todos
    case VisibilityFilters.SHOW_COMPLETED:
      return todos.filter(t => t.completed)
    case VisibilityFilters.SHOW_ACTIVE:
      return todos.filter(t => !t.completed)
    default:
      throw new Error("Unknown filter: " + filter)
  }
}
// 將store中的state作為props傳遞給被包裹組件
// mapStateToProps對應當前組件所需要的props,不過這個props顯然是要從store中抽取的,不是所有store都需要,所以只會取state.todos 
const mapStateToProps = state => ({
  todos: getVisibleTodos(state.todos, state.visibilityFilter)
})
// 將action 與被包裹組件相綁定。
// 其實就是將action中的方法賦值到Props上,以便在組件中調用toggleTodo方法
const mapDispatchToProps = dispatch => ({
  toggleTodo: id => dispatch(toggleTodo(id))
})
// 被包裹組件就對應TodoList
export default connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)
具體實現

connect實現比較復雜一點,返回的是個高階函數我們可以先看該函數實現了什么。

connect函數

首先該方法接受相關參數,進行參數的判斷和兼容處理(不指定使用默認)。 并返回一個 wrapWithConnect 方法來裝飾傳入的容器組件。

// 每個參數的默認實現
const defaultMapStateToProps = state => ({}) // eslint-disable-line no-unused-vars
const defaultMapDispatchToProps = dispatch => ({ dispatch })
const defaultMergeProps = (stateProps, dispatchProps, parentProps) => ({
  ...parentProps,
  ...stateProps,
  ...dispatchProps
})

export default function connect(mapStateToProps, mapDispatchToProps, mergeProps, options = {}) {
  // 需要store中的state才會去監聽
  const shouldSubscribe = Boolean(mapStateToProps)
  // 更新state 方法的兼容,無mapStateToProps則使用默認
  const mapState = mapStateToProps || defaultMapStateToProps

  let mapDispatch
  // action creater是否為 函數
  if (typeof mapDispatchToProps === "function") {
    // 函數直接賦值
    mapDispatch = mapDispatchToProps
  } else if (!mapDispatchToProps) {
    // 不存在,則使用默認方法
    mapDispatch = defaultMapDispatchToProps
  } else {
    // 否則 將action Creater 包裝起來
    mapDispatch = wrapActionCreators(mapDispatchToProps)
  }

  const finalMergeProps = mergeProps || defaultMergeProps
  const { pure = true, withRef = false } = options
  const checkMergedEquals = pure && finalMergeProps !== defaultMergeProps
function wrapWithConnect(WrappedComponent) {
    const connectDisplayName = `Connect(${getDisplayName(WrappedComponent)})`
     class Connect extends Component {/****/}
    // ****
    return hoistStatics(Connect, WrappedComponent)
    }

wrapWithConnect 函數 返回內容

wrapWithConnect 函數接受一個組件(connect這就是個HOC。返回一個connect組件

// ****省略*****
// hoistStatics的作用:常用語高階組件中,將被包裹元素的靜態方法,“同步”到容器元素中。
// 也就是 connect中那些WrappedComponent屬性的mix
return hoistStatics(Connect, WrappedComponent)

這里,就是HOC常見的增加功能的實現了。 也就是增強與redux的關聯,讓使用者只需要關注props,而非每次都要自己手動綁定。

connect組件生命周期

既然connect存在生命周期,那就順著生命周期看看

構造函數,就是獲取store中的state。

this.store 即Provider中掛載的Store

// 構造函數,獲取store中的state
      constructor(props, context) {
        super(props, context)
        this.version = version
        // props或者context中,這是provider中掛載的store
        this.store = props.store || context.store
        
        //  獲取state
        const storeState = this.store.getState()
        // 初始化state
        this.state = { storeState }
        this.clearCache()
      }

shouldComponentUpdate

shouldComponentUpdate這里會根據options里面的參數來看是否 pure 選擇不同的更新策略

shouldComponentUpdate() {
        return !pure || this.haveOwnPropsChanged || this.hasStoreStateChanged
      }

componentDidMount

componentDidMount 根據前面的shouldSubscribe標識(mapStateToProps是否為true)決定是否增加監聽事件

componentDidMount() {
       this.trySubscribe()
     }
trySubscribe() {
       // 存在監聽必要 并且沒有注冊過監聽事件
       if (shouldSubscribe && !this.unsubscribe) {
         // 業務組件中沒有使用的subscribe 在這里實現,這也是HOC的用法之一,公共方法的抽離
         // 注冊完成之后,this.unsubscribe為對一個unsubscribe回調
         this.unsubscribe = this.store.subscribe(this.handleChange.bind(this))
         this.handleChange()
       }
     }    

componentWillReceiveProps

componentWillReceiveProps 判斷是否更新 ,對于pure 組件 這里就涉及到了shallowEqual。 通過shallowEqual的實現,我們可以得到Immtable的重要性

componentWillReceiveProps(nextProps) {
        if (!pure || !shallowEqual(nextProps, this.props)) {
          this.haveOwnPropsChanged = true
        }
      }

shallowEqual淺比較的實現

由此可以看到Immutable的重要性。對于引用類型的數據,只是比較了引用地址是否相同。
對于嵌套引用數據類型,只比較key的長度和value引用地址,并沒有進一步深入比較。導致嵌套結構并不適用。

export default function shallowEqual(objA, objB) {
  // 引用地址是否相同
 if (objA === objB) {
   return true
 }

 const keysA = Object.keys(objA)
 const keysB = Object.keys(objB)
 // key長度是否相同 
 if (keysA.length !== keysB.length) {
   return false
 }
 // 循環比較,vakue思否相同,對于嵌套引用類型,這種比較是不能滿足預期的。
 const hasOwn = Object.prototype.hasOwnProperty
 for (let i = 0; i < keysA.length; i++) {
   if (!hasOwn.call(objB, keysA[i]) ||
       objA[keysA[i]] !== objB[keysA[i]]) {
     return false
   }
 }

 return true
}

render

再下面是render,對于是否更新進行判斷,即是否更新傳遞給子組件的props render的關注點在于 傳遞給WrappedComponent的props如何獲得。

// this.mergedProps 的計算
if (withRef) {
         this.renderedElement = createElement(WrappedComponent, {
           ...this.mergedProps,
           ref: "wrappedInstance"
         })
       } else {
         this.renderedElement = createElement(WrappedComponent,
           this.mergedProps
         )
       }

計算this.mergedProps 最終傳遞下去的props是經過mapStateToProps,mapDispatchToProps計算之后,最后再由mergeProps計算之后的state。

// 簡化代碼
this.mergedProps = nextMergedProps = computeMergedProps(this.stateProps, this.dispatchProps, this.props)

  /**
     * 獲得最終props 即經過參數中的
     * @param {*} stateProps 經過mapStateToProps之后的結果
     * @param {*} dispatchProps mapDispatchToProps之后的結果
     * @param {*} parentProps 此處即為connect組件的props this.props
     * @returns
     */
    function computeMergedProps(stateProps, dispatchProps, parentProps) {
      // finalMergeProps 即為參數中的mergeProps 或者 defaultMergeProps。 將前兩參數計算結果再進行處理。
      const mergedProps = finalMergeProps(stateProps, dispatchProps, parentProps)
      if (process.env.NODE_ENV !== "production") {
        checkStateShape(mergedProps, "mergeProps")
      }
      return mergedProps
    }

到這里connect的作用也體現出來了:

    根據參數決定監數據的變化

    將store和action作為warpered的props傳入,一共組件使用store中的state和action

    對于部分操作進行緩存優化,提升執行效率

此時再回過頭去看上面的例子應該更清晰了。

結束語 參考文章

cn.redux.js.org/docs/react-…

到這里就結束了react-redux的源碼解析,更多是自己的學習筆記吧。
使用一定程度之后再回頭看,可能對自己的理解更有幫助。
另外閱讀源碼不是要盲目去讀,而是在應用之后帶著問題去讀。 這樣會更清晰如何去優化如何去提升。因為水平有限肯定有錯漏指出,歡迎指出。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/6802.html

相關文章

  • react-redux用法及源碼解讀

    摘要:帶有內部狀態,內部可以使用。代表監聽的全局,也可以說是全局的,表示該組件自身攜帶的方法。回答問題是通過應用的,將通過頂層組件傳遞到上下文環境中。所有頁面集合緩存不用每次都重新加載通過綁定用法完參考文章 react-redux把組件分為UI組件和容器組件。先看圖下圖: showImg(https://segmentfault.com/img/bVbkVBz?w=1378&h=1194);...

    Zoom 評論0 收藏0
  • 重讀redux源碼(二)

    摘要:函數組合,科里化的串聯結合示例源碼,實現也很優雅,對于返回的,將等參數傳遞進去,然后執行,等待回調異步完成再。對于正常對象則進行下一步。前言 作為前端狀態管理器,這個比較跨時代的工具庫redux有很多實現和思想值得我們思考。在深入源碼之前,我們可以相關注下一些常見問題,這樣帶著問題去看實現,也能更加清晰的了解。 常見問題 大概看了下主要有這么幾個: redux三大原則 這個可以直接參考...

    dingda 評論0 收藏0
  • React-redux基礎

    摘要:簡介創建的函數,返回一個對象,包含等方法合并多個中間件處理,在實際的前調用一系列中間件,類似于綁定和函數式編程中常見的方法,介紹官方提供的綁定庫。 前言 在學習了React之后, 緊跟著而來的就是Redux了~ 在系統性的學習一個東西的時候, 了解其背景、設計以及解決了什么問題都是非常必要的。接下來記錄的是, 我個人在學習Redux時的一些雜七雜八~ Redux是什么 通俗理解 h...

    jsyzchen 評論0 收藏0
  • 走近 Redux

    摘要:的核心思想就是維護一個單向數據流,數據的流向永遠是單向的,所以每個步驟便是可預測的,程序的健壯性得到了保證。另外,還有一點比較重要的是,因為沒有了一個一直保存更新的狀態對象,所以在中的也就沒有意義了,通過可以完全實現一個順暢的數據流。 1 Redux Redux is a predictable state container for JavaScript apps 簡單來說,Redu...

    fevin 評論0 收藏0
  • [源碼解讀] react-redux

    摘要:本文并不逐行地對源碼進行細致分析,不如說是基于以下幾個問題,對源碼進行大致的掃覽。我們已經知道,中,允許用戶注冊監聽器,這些監聽器會在每次執行結束后遍歷觸發。省略一些無關代碼其中,是為了在嵌套的中嵌套執行。 react-redux 源碼解讀 [TOC] 前置知識 閱讀本篇文章前,請先確認你是否了解以下知識: react redux 高階組件 react diff 機制 其中高階組件...

    Olivia 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<