1. 程式人生 > >redux和react-redux

redux和react-redux

react的流程:

1. 可以看到,一般都是團長等高階幹部商量好對策之後(this.state設定好)

2. 把命令一層層的傳遞下去執行(this.props渲染)

3. 要是哪裡發生了什麼新的敵情了(想更新頁面內容了)

.就得一層層往上報告(通過回撥一層層把資料傳上去),此過程也必須一層層往上傳遞,不能越級,下面有解釋

5. 團長做出決斷後再發布命令傳下去執行(通過setState修改資料並重新渲染)

 

這個過程是不能越級的,比如說你一連長髮現了敵情就不能直接報告團長,而必須先報告給一營長,一營長再報告給團長,這裡層級還不是特別深,你再來個排長,班長什麼的,按照這種模式,等團長知道敵情,敵人都打到家門口啦,又或者說一連長想找三連長喝個酒,還得先把這個訊息傳給營長,再傳給團長,再傳給二營長再傳給三連長,這……

 

Redux橫空出世

所以說層級不深,組價之間也沒有什麼公用資料的時候,用React自身的setState其實也可以了,可是巢狀一深,或者元件有一些公用資料時就比較麻煩了,於是就有了redux(其實之前還有個flux),回到這個例子就是,他們在整個團之外又建立了一個通訊班(Redux)

 

分清兩個state

在說Redux之前,我想說一下自己學的時候遇到的一個小坑,就是Redux中的state和React中的state完全不是一回事,React中的state是元件內部自己的狀態資訊,而Redux中的state是Redux自己的資料,然後React就拿Redux中的資料來用,其實Redux也可以在其他框架下使用,並不是非要跟React一起使用。

簡單畫個圖看起來就像下面這樣:

這裡只是一個很簡單的示意圖,實際使用並非如此,這個圖示為了讓大家理解React中的資料和Redux中的資料是獨立的,並沒有半毛錢關係

 

Redux

現在讓我們拋開戰鬥編制(React),單看通訊班(Redux)。

其實網上講Redux的教程非常多,這裡就簡單說一下:

store

store:首先要建立一個物件store,這個物件有各種方法,用來讓外界獲取Redux的資料(store.getState),或者讓外界來修改Redux中的資料(store.dispatch)

import { createStore } from
'redux'; const store = createStore(reducer);

action

action:描述我要幹啥,一般是一個物件的形式,其中有一個type欄位是必須要有的,比如:{ type:‘請求增援’ },還可以帶點資料{ type:‘請求增援’,gun:"100" }

reducer

reducer:擼開袖子真刀實槍的就去幹了,比如一連長要求增援,增援要求是100杆槍,團長馬上就給你加了100杆槍送了過去。

const defaultState = 0;
const reducer = (state = defaultState, action) => {
  switch (action.type) {
    case '請求增援':
      return state + action.gun;
    default: 
      return state;
  }
};

action和reducer也可以想象成產品經理和程式設計師的關係。

產品經理:“我要一個按鈕,圓角的”

程式設計師:“嗯,做好了”

產品經理:“換個顏色吧,紅色”

程式設計師:“ok,換好了”

差不多就是這樣,產品經理並不操心具體怎麼實現的,他只說他想要幹什麼(type),然後再提點實現的要求(各種其他的資料),程式設計師就去具體實現(reducer,修改state,然後返回一個全新的state,這裡注意我們並沒有直接返回原來的state,我們返回的是一個全新的state物件,因為reducer函式是一個沒有副作用的純函式)

那怎麼去觸發這個操作(action)呢,就好比說我一連長髮現敵情了,我怎麼報告給通訊班,讓通訊班來處理呢?

就是上面提到過的store.dispatch,不過還要加一個引數,那就是action

store.dispatch({ type:‘請求增援’,gun:"100" })

這樣就可以觸發action,執行reducer,得到一個全新的state。

 

Redux 和 React

到此為止,Redux自己就折騰完了,那麼Redux自己的資料並沒有用,它要把資料交給React用才行,接下來講一講怎麼把資料交給React來用。

上面我們建立了一個物件store,我們要把這個store物件作為props傳給React,那React就可以用了。

這個store只能有一個,也就只能建立一次,也就是說你必須在最頂層處建立一個store物件,然後再一層層的傳遞下去,才能讓所有的元件都能獲得這個store物件,呼叫它的方法。

獲取Redux中的資料

比如說我要在render函式中顯示Redux的資料,那麼我就可以先獲取它的資料:

store.getState()

然後把這個資料當做props渲染到元件中去就行了。

 

更新Redux中的資料

如果你要修改它的資料,那就在JSX中呼叫

store.dispatch( { type:‘請求增援’,gun:"100" } )

這個函式可以監聽Redux中state的變化,一旦Redux中的state發生了變化,render函式就會被呼叫,頁面就會被重新渲染。

 

上面這個過程就是手動呼叫的過程,但這樣呼叫有點麻煩,因為要讓所有的子元件都能應用store中的資料,那麼所有的元件就都要把store當做props傳進來,這也太麻煩了。

還是那之前那個例子來說,你一連長髮現了敵情,是不用層層上報了,可以直接報告給通訊班,通訊班再生成新的命令,可問題是,你從下往上打報告是簡單了,可是從上往下發布命令仍然是一層層的傳遞的呀。

就好比說,一連長髮現了敵情,報告上去,通訊班做出決定讓三連長帶人去打,通訊班還是得通過團長--營長--連長這條路去一層層釋出命令,能不能讓通訊班直接就通知三連長呢,當然是有的,這就是我們的React-redux庫

 

React-redux

這個是需要你自己去用npm額外安裝的。

使用這個方法之後,我們就不需要一層層往下發布命令了

在React-redux中有兩個比較關鍵的概念:Provider和connect方法。

一般我們都將頂層元件包裹在Provider元件之中,這樣的話,所有元件就都可以在react-redux的控制之下了,但是store必須作為引數放到Provider元件中去

<Provider store = {store}>
    <團長/>
<Provider>

這個元件的目的是讓所有元件都能夠訪問到Redux中的資料。

 這個比較簡單,我們主要講connect方法。

 

connect方法:

connect(mapStateToProps, mapDispatchToProps)(MyComponent)

其實connect方法一共有4個引數,這裡主要講前兩個。

mapStateToProps

字面含義是把state對映到props中去,意思就是把Redux中的資料對映到React中的props中去。

也就是說你React想把Redux中的哪些資料拿過來用。

比如這裡二連這個元件想要渲染自己槍支的數量。就可以直接在二連這個元件中把Redux中的gunOfErlian拿過來用

const mapStateToProps = (state) => {
  return {
    gun: state.gunOfErlian
  }
}

然後渲染的時候就可以直接使用this.props.gun

class Erlian extends Component {
    constructor(props){
        super(props);
    }
    render(){
        return(
            <div>this.props.gun</div>
        )
    }
}
Erlian = connect()(Erlian);
export default Erlian;

那麼這樣就可以實現渲染,就是把Redux中的state變成React中的props。

 

mapDispatchToProps

通過上面的分析,相信這個函式也很好理解,就是把各種dispatch也變成了props讓你可以直接使用

然後就到了我們這裡最重要的一點了。

const mapDispatchToProps = (dispatch) => {
  return {
    onClick: () => {
      dispatch({
        type: '請求增援',
     gun : 100
      });
    }
  };
}

更改一下上面的Erlian元件

class Erlian extends Component {
    constructor(props){
        super(props);
    }
    render(){
        return(
            <div>this.props.gun</div>
            <button onClick = {this.props.onClick}>請求增援</button>
        )
    }
}
Erlian = connect()(Erlian);
export default Erlian;

當我點選請求增援按鈕後,Erlian元件的槍支數量會自動的更新,而不需要我們手動的去用store.subscribe訂閱render函式以達到更新頁面的目的。

這樣一來我們就不需要一層層的傳遞store物件了。

這種隨處都可以使用、修改Redux中的資料的方式確實很方便,但Redux推薦的最佳實踐還是在儘可能少的地方使用connect,把邏輯,資料相關的都放到容器元件中去處理,其他的元件都由容器元件所生成的props一層層傳遞下去然後渲染(傻瓜元件),這裡就不多說了。

這一次的小結差不多就這樣了,許多程式碼細節部分都沒有寫,更多的是對他們的作用的理解,因為自己在學習的時候,更多的是一些理解方面的困惑,而更多更全面的程式碼部分在Redux官方文件或是阮一峰老師的部落格中都已經寫得非常清楚,大家可以去看看,理解了上面許許多多的名詞以及他們的含義之後,相信那些文件會更容易看懂。