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


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

篇幅過長,多分了幾篇。

1. Redux簡單實現


這里先不考慮中間件機制

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重點的方法就是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/qwe

2.react中的context


要理解react-redux原理,必須先說下react中的context。父組件向子組件傳遞數據,可以通過props,如果層級比較深呢?就不好了,會有性能問題,我們可以通過context來實現跨級傳遞數據。

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組件。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM