關(guān)于Redux為核心的應(yīng)用開發(fā)簡(jiǎn)介


title: 關(guān)于Redux為核心的應(yīng)用開發(fā)簡(jiǎn)介
date: 2017-04-20 08:05:04
categories: React-native
tags: Redux


問題出發(fā)點(diǎn),當(dāng)我們?cè)赨I組件中執(zhí)行交互操作(點(diǎn)擊,滑動(dòng),提交),我們要考慮到怎么來響應(yīng)操作.函數(shù)式編程里有個(gè)圖,有一個(gè)機(jī)器,從一邊放入肉,另一邊出火腿.這就是一個(gè)流程.application的操作其實(shí)就是解決點(diǎn)擊=>結(jié)果展示的流程.
但是實(shí)際流程中需要解決的問題很多.我們要考慮怎么來更好的管理application 的狀態(tài)問題. 具備javascript的基礎(chǔ)知識(shí),幾個(gè)模式設(shè)計(jì)的東西,函數(shù)式編程的知識(shí),React的知識(shí),Redux的思想.可以說想在實(shí)際應(yīng)用中玩轉(zhuǎn)React/Redux/Redux-saga/immutable。需要掌握的東西還是很多的.
我先寫一點(diǎn)具體的一些學(xué)習(xí)內(nèi)容和需要的思想.

輔助觀念轉(zhuǎn)變的一個(gè)生活實(shí)例

先看個(gè)電燈電路

電燈的原理圖
電燈的原理圖
  1. 控制開關(guān)執(zhí)行動(dòng)作(操作),
  2. 電燈根據(jù)開關(guān)的動(dòng)作來改變狀態(tài),
  3. 電燈的狀態(tài)不是由自己決定的,電路里有電了就會(huì)亮,沒電了就不亮,像木偶一樣受到控制.

飛機(jī)座艙

早期的座艙
早期的座艙

各個(gè)儀表都和自己的傳感器連接在一起,加上冗余備份的儀表,很難設(shè)計(jì)和維護(hù)

先進(jìn)座艙
先進(jìn)座艙

80-90年代的window操作系統(tǒng)(不止windows奧),起源其實(shí)就是早期美國(guó)國(guó)防部的科研項(xiàng)目.
傳感器和顯示屏就沒有那么多線了.由數(shù)據(jù)總線來做集中統(tǒng)一處理.

理解React/Redux/Redux-saga架構(gòu)的基礎(chǔ)知識(shí)

函數(shù)式編程思想

函數(shù)式編程想的模擬香腸機(jī)器
函數(shù)式編程想的模擬香腸機(jī)器

函數(shù)式編程把流程拆為幾個(gè)有聯(lián)系的步驟,可以分解流程,易于維護(hù).合起來完成一個(gè)具體的任務(wù).
但是這只是函數(shù)式編程的一個(gè)組成部分
在javascript的函數(shù)式編程中用到很多概念

  1. 函數(shù)作為一類對(duì)象,可以作為數(shù)組的元素,可以作為函數(shù)的參數(shù)來傳遞.
  2. 基于流的編程(redux-saga就是基于流的編程).
    基于流的編程
    基于流的編程
  3. 閉包的概念


    閉包的概念圖
    閉包的概念圖
一個(gè)簡(jiǎn)單的閉包函數(shù)
一個(gè)簡(jiǎn)單的閉包函數(shù)

作為工具函數(shù)的閉包
作為工具函數(shù)的閉包
  1. high-order function 接受其他函數(shù)作為參數(shù)的函數(shù)
  2. 純函數(shù),對(duì)象的immutable,狀態(tài)改變.

一個(gè)實(shí)際的流程分析

在用戶提交表單的時(shí)候,我們想要做如下事情:

1. 校驗(yàn)一些輸入信息 (簡(jiǎn)單, 寫在組件里)
Validate方法,可以考慮導(dǎo)入redux-form組件,自帶驗(yàn)證方法
2. 驗(yàn)證以后可以讓提交按鈕改為可以提交狀態(tài)了
```
//login.UI.js登錄組件
this.props.dispatch(userLoginRequest(submit_info));
//已經(jīng)結(jié)束了,不要想太多,用戶和組件的交互就是表單輸入和提交按鈕
//所以這里也執(zhí)行這個(gè)過程就可以了.

 ```

3. 彈起提示信息(React組件化的優(yōu)勢(shì),公共組件)

```
   //login.Ui.js
  //Lodaing組件
 this.props.isFetching?<Loading>:null
 
```

4. 提交后端服務(wù) (我們用fetch,這個(gè)是不變的,redux只是對(duì)流程的控制,并不是要改變實(shí)際做事的方法)

5. 拿到后端返回狀態(tài) (promise resolve)
6. 隱藏提示信息 (鴻門宴啊,摔杯為號(hào),這不就是狀態(tài)嗎?)

 ```
   //login.UI.js
   this.props.isFetching?<Loading>:null
 
  ``` 

7. 更新redux store (reducer的操作)

  //login.reducer.js
  
  return state.merge(resolve.result);
  

8. 登錄界面的任務(wù)完成了.根據(jù)業(yè)務(wù)需要跳轉(zhuǎn)到對(duì)應(yīng)的頁(yè)面

  //reducer.js
  
  return state.merge(resolve.result);
  
  //login.js
  
  this.props.loginsuccess?(Action.Mycenter):(Action.refresh)
  

這里我們就把登錄的流程做了分解.好處是很多的,流程都是根據(jù)狀態(tài)來的變化的,
代碼書寫清晰,在每一步的dubug和測(cè)試過程都很容易,因?yàn)槲覀兛梢垣@取每一步的狀態(tài)

由于有redux-logger的中間件存在,我們還可以查看每一步的狀態(tài)變化.好像還有圖形化的界面來顯示state的變化.

總的原則是React組件只負(fù)責(zé)信息展示,簡(jiǎn)單的驗(yàn)證
復(fù)雜的邏輯現(xiàn)在全部在Redux中來實(shí)現(xiàn)

副作用(side effect)到底是個(gè)什么?

副作用其實(shí)就可以理解為由外部API提供的服務(wù).這個(gè)服務(wù)和我們的app的流程是沒有關(guān)系的,我們只需要給接口提供參數(shù),等待接口返回?cái)?shù)據(jù)就可以了.

React/Redux/Redux-saga

React的概念,原理

  1. React內(nèi)心是虛擬DOM,在react中的html代碼實(shí)際是React渲染的模板


    react組件中的html代碼叫jsx代碼,不是實(shí)際的html代碼,是js代碼
    react組件中的html代碼叫jsx代碼,不是實(shí)際的html代碼,是js代碼
  2. React渲染動(dòng)態(tài)內(nèi)容的方式通過外部父組件傳入的props和組件內(nèi)部的state來實(shí)現(xiàn)
    絕對(duì)不可以搞錯(cuò)的概念:組件之間要傳遞參數(shù)只能通過props來實(shí)現(xiàn),state只能在組件內(nèi)部使用,如果要把sate傳遞到其他組件,一定要經(jīng)過轉(zhuǎn)換
    在React中,props和state都有兩類不同的id來區(qū)分,不同的id類型是找不到對(duì)方的內(nèi)容的.Redux的mapStateToProps方法就是把State的類型id轉(zhuǎn)為props的類型id.
    由此可以得出什么結(jié)論呢?

其實(shí)Redux也是一個(gè)React的組件.

Redux的mapStateToProps函數(shù)的主要目的是什么?
Redux的mapStateToProps函數(shù)的主要目的是什么?

******切記,切記*******

3.Connect這個(gè)函數(shù)是非常重要的函數(shù)
組件要訂閱state的變化,能夠訂閱dispatch的方法都是通過connect函數(shù)來執(zhí)行的.

Redux的出現(xiàn)

Redux的流程圖
Redux的流程圖

Redux負(fù)責(zé)把React的邏輯處理獨(dú)立出來處理
Redux的要點(diǎn)有:

  1. 一個(gè)應(yīng)用只有一個(gè)state
  2. state是只讀的,這是immutable的概念.
  3. 修改state只能是用純函數(shù)來執(zhí)行,dispatch(Action(params))

一旦React的應(yīng)用中加入Redux的構(gòu)架以后,所有Appliction的核心就由組件轉(zhuǎn)變到Redux中了.如果和傳統(tǒng)的web的 browser/server來類比,Redux就變成了服務(wù)器的角色,state就承擔(dān)了數(shù)據(jù)庫(kù)的角色.

組件之前的state的改變現(xiàn)在要重新思考了.

Redux承擔(dān)了服務(wù)器和數(shù)據(jù)庫(kù)的角色
Redux承擔(dān)了服務(wù)器和數(shù)據(jù)庫(kù)的角色

組件之間就最好再也不要做數(shù)據(jù)的傳遞,組件要執(zhí)行渲染的sate統(tǒng)一從Redux的store中獲取.
這一步思考方法的改變是極為重要的.

如果一個(gè)流程的過程非常的復(fù)雜,我們應(yīng)該怎么來處理?

這一點(diǎn)其實(shí)有很多的解決辦法,但是Redux-saga基本算是非常優(yōu)秀的解決辦法,嚴(yán)格貫徹了函數(shù)流式編程的思想,把一個(gè)復(fù)雜邏輯處理為一個(gè)數(shù)據(jù)流.

Redux-saga就是我們的救世主

redux-saga把我們上面的所有登錄的流程可以寫到一個(gè)工作流里面,香腸機(jī)器的組裝

 //login.saga.js
 import {loginReuest loginFetching,loginSuccess,loginError } from '../actions/login';
 //請(qǐng)求登錄的數(shù)據(jù)流過程
export function* loginRequestFlow(submit_info) {
  try {
    yield put(loginFetching(isFetching:true))
     const userInfoFromRemoteService = yield call(request,submit_info,'get');
    yield put(loginSuccess(userInfoFromRemoteService));
    const errorMessage = articleList.showapi_res_error;
    if (errorMessage && errorMessage !== '') {
      yield toastShort(errorMessage);
    }
  } catch (error) {
    yield put(loginSuccess([]));
    toastShort('網(wǎng)絡(luò)發(fā)生錯(cuò)誤,請(qǐng)重試');
  }
}

export function* watchuserLoginRequest(sumbit_info) {
  while (true) {
    const {
      sumbit_info
    } = yield take(types.loginRequest);
    yield fork(loginRequestFlow, );
  }
}


//login.action.js
export function userLoginRequest(sumbit_info){
   return {
     types.loginRequest,
     sumbit_info
   }
}
 
Redux-saga把登錄的流程變?yōu)橐粋€(gè)函數(shù)流操作,所有有關(guān)的操作都在這里面實(shí)現(xiàn)
Redux-saga把登錄的流程變?yōu)橐粋€(gè)函數(shù)流操作,所有有關(guān)的操作都在這里面實(shí)現(xiàn)

Redux會(huì)監(jiān)視這個(gè)數(shù)據(jù)流的觸發(fā)

Redux-saga通過監(jiān)控特定的ActionType來觸發(fā)操作
Redux-saga通過監(jiān)控特定的ActionType來觸發(fā)操作

Redux saga 暴露了幾個(gè)方法,稱為 Effects,定義如下:

Fork 執(zhí)行一個(gè)非阻塞操作。

Take 暫停并等待action到達(dá)。

Race 同步執(zhí)行多個(gè) effect,然后一旦有一個(gè)完成,取消其他 effect。

Call 調(diào)用一個(gè)函數(shù),如果這個(gè)函數(shù)返回一個(gè) promise ,那么它會(huì)阻塞 saga,直到promise成功被處理。

Put 觸發(fā)一個(gè)Action。

Select 啟動(dòng)一個(gè)選擇函數(shù),從 state 中獲取數(shù)據(jù)。

takeLatest 意味著我們將執(zhí)行所有操作,然后返回最后一個(gè)(the latest one)調(diào)用的結(jié)果。如果我們觸發(fā)了多個(gè)時(shí)間,它只關(guān)注最后一個(gè)(the latest one)返回的結(jié)果。

takeEvery會(huì)返回所有已出發(fā)的調(diào)用的結(jié)果。

Redux-saga并沒有改變Redux對(duì)于state的處理,只不過借用了es6/es7的方法對(duì)一個(gè)相關(guān)流程的changeState函數(shù)進(jìn)行了包裝而已.

所以理解Redux-saga的工作原理,對(duì)于React和Redux工作原理理解是前提.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容