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