Redux和React-Redux的實現(一):Redux的實現和context

react使用redux作狀態管理,實現多個組件之間的信息共享,解決了父子組件、兄弟組件之間的複雜通訊問題。vue有vuex,總之是一種flux的思想。react提供了react-redux這個庫,一看名字就知道是爲了將react和redux關聯起來,react-redux有connect高階函數以及Provider組件、milddleware、thunk等,來實現一下。vue

篇幅過長,多分了幾篇。react

1. Redux簡單實現


這裏先不考慮中間件機制vuex

import { createStore } from 'redux'

function counter(state = 10, action) {
  console.log(state, action)
  switch (action.type) {
    case 'add':
      return state + 1
    case 'less':
      return state - 1
    default:
      return state
  }
}

const store = createStore(counter)

const init = store.getState()
console.log(`Init count: ${init}`)

function listener(){
  const current = store.getState()
  console.log(`count: ${current}`)
}
store.subscribe(listener)

store.dispatch({ type: 'add' })
store.dispatch({ type: 'less' })

這是redux簡單的例子,首先咱們定義了一個reducer叫作counter,接下來使用redux提供的createStore方法將reducer傳入,構造出了一個store,而後基於觀察者模式,觸發相應的action,進行相應的響應。redux

Redux重點的方法就是createStore、getState、subscribe、dispatch這四個方法。大致講一下思路,咱們的Redux,這裏就叫myRedux,myRedux和Redux同樣,都是隻暴露出來一個方法,那就是createStore,而後createStore保存着一個state,能夠是對象、字符串、數組等,能夠經過getState方法來訪問state,還有對state的監聽器以及訂閱的方法,實現一下。數組

export function createStore (reducer) {
  let state = {}
  let listeners = []

  function getState () {
    return state
  }
  function subscribe (listener) {
    listeners.push(listener)
  }
  function dispatch (action) {
    state = reducer(state, action)
    listeners.forEach(listener => listener())
    return action
  }
  // 爲了確保createStore以後,store.getState中就有state的初始值
  dispatch({type: '@myRedux/qwe'})
  return {getState, subscribe, dispatch}
}

其實就是一個觀察者模式,值得注意的是:當執行完createStore以後,執行stroe.getState方法就能獲取到初始的狀態(咱們這裏是10),因此須要咱們的reducer先執行一次,那麼咱們就要在createStore中就先dispatch一下,代碼中有體現。Redux中也是這麼作的,Redux初始化dispatch的type值是@@redux/INIT,能夠看一下。安全

這麼作是爲了確保初始化dispatch的type值不會和用戶定義的type值重複,咱們代碼裏type爲@myRedux/qweless

2.react中的context


要理解react-redux原理,必須先說下react中的context。父組件向子組件傳遞數據,能夠經過props,若是層級比較深呢?就很差了,會有性能問題,咱們能夠經過context來實現跨級傳遞數據。ide

context是全局的,在組件中聲明,全部的子組件均可以獲取到context,react以爲全局不是很安全,因此要求context都是強數據類型,即任何想訪問context裏面的屬性的組件都必須指定一個contextTypes的屬性,若是沒有指定該屬性的話,用this.context訪該屬性就會出錯。函數

一樣,經過getChildContext方法指定傳遞給子組件的屬性也須要被指定數據類型,經過childContextTypes來指定,不指定一樣會產生錯誤。性能

下面是一個簡單例子。

import React from 'react'
import PropTypes from 'prop-types'

class Son extends React.Component{
    render(){
            return (
                <div>
                    <p>子組件</p>
                    <GrandSon/>
                </div>
            )
    }
}

class GrandSon extends React.Component{
    static contextTypes = {
        user:PropTypes.string
    }
    render(){
        console.log(this.context)
        return (
                <div>
                    <p>孫組件</p>
                    <div>孫組件收到來自父組件的信息:{this.context.user}</div>
                </div>
        )
    }
}

class Father extends React.Component{
    static childContextTypes = {
        user:PropTypes.string
    }
    constructor(props){
        super(props)
        this.state = {user:'user12'}
    }
    getChildContext(){
        return this.state
    }
    render(){
        return (
            <div>
                <p>父組件,要給孫組件:{this.state.user}</p>
                <Son/>
            </div>
        )
    }
}

export default Father

在這裏就不須要經過props一層一層的往下傳遞屬性了,這就是context。

3.Provider組件


那麼context和咱們的react-redux有什麼關係呢,用過的都知道,Provider組件在整個應用組件上包了一層,讓整個應用組件成爲Provider的子組件,看到這裏,你是否是有點懂了,跟上面的例子很像嘛,對的,就是這樣,咱們的Provider組件接收Redux的store做爲props,經過context對象傳遞給子組件。

咱們下一篇就會說道Provider組件。

相關文章
相關標籤/搜索