1. 程式人生 > >Redux中介軟體在React和React-Native專案架構中的應用實踐

Redux中介軟體在React和React-Native專案架構中的應用實踐

這裡寫圖片描述

前言

在MVVM框架模式獨攬天下的今天,React憑藉其獨特的設計思想,深入的設計理念,開闢了一條嶄新的康莊大道,實屬是一個重大的突破,為什麼這麼說呢?因為React論其設計思想,充其量只是MVVM種的V而已,對於大量而且複雜的資料來講,自身處理上顯得有些力不從心,這時候,傳統的Redux和Flux的設計思想起到了決定性的作用,對於Redux和Flux這裡不多贅述,這個觀念在這兩年被炒的異常火熱,網上我們可以搜到很多的資源,最重要的是,單向資料流的觀念越來越被眾多的開發者應用於專案架構之中,一定程度上來講這種設計思想,很大程度上提升了應用的效能,對此我就來談談我再React專案中的應用實踐以及相應的觀點。

react-redux分析

其實,Redux和React兩個框架之間並沒有絕對的聯絡,他們都是獨立的JS框架,一個出於View層,一個用於state管理,兩者之間可以相互使用,但是API融合度並不是很高,使用起來不是特別的方便,於是便有了React-redux, 藉助react-redux這個庫提供一些封裝,一種更科學的程式碼組織方式,讓我們更舒服地在React的程式碼中使用Redux。

react-redux主要提供的常用介面有:

  1. provider: Provider這個模組是作為整個App的容器,在你原有的App Container的基礎上再包上一層,用於傳遞props。

  2. connect:

    連線Redux和React。

Store的作用與分析

store翻譯過來講就是儲存,這個模組有redux提供,而不是react-redux, 主要用於儲存應用所有的state。類似於一個大的臨時儲存資料庫。

建立程式碼也很簡單:

....
import { applyMiddleware, createStore, compose } from 'redux';
....
const store = createStore(reducers, undefined, middlewares);
.....
.....

Action的作用分析

action顧名思義就是各種操作,對於redux來講,view的每一種處理都會對應一種操作,每個action的定義也很簡單,主要變數是一個type,定義了當前action是處理什麼的。

view ==> dispatch ===> action

通常,也有開發者會在action中訪問請求資料,比如http資料請求等等。

看下程式碼:

const loginAction = (data) => {
    return {type: LOGIN_REQUEST, payload: data}
}

上面這個action可以通過dispatch進行分發處理到對應的reducers.

Reducer的作用

上面講到action會定義各種操作,比如登陸,驗證等等,那麼接下來資料會怎麼處理,進一步更新state呢?

這就要提到reducer的作用了,reducer主要處理各種資料邏輯,篩選,過濾等操作,處理完成後,會返回一個新的state,在更新到view上顯示。

所以reducer的作用,在整個環節還是至關重要的。

我們看一個reducer的程式碼:

import { handleActions } from 'redux-actions';
import * as types from './word-constants';
import { combineReducers } from 'redux';


const getJokesList = handleActions({
        [types.SUCCESS_FETCH_DATA]: (state, action) => {
                state = action.payload;
                console.log(action.payload);
                return [...state];
        }
}, []);

export default combineReducers({getJokesList});

上面程式碼中,我們暫且不管handleAcions的作用,主要看state的處理,這裡傳遞給state一個新的資料,最後通過拓展運算子…返回。

當然這只是一個例子,真實專案中可能要處理很複雜的資料結構。

applyMiddleware分析

redux在react的專案中,角色主要是資料管理,既然是資料管理,就是多少會有點中介軟體的意思,所以也有很多人說,redux在react專案架構中就是一箇中間件的角色,這個我很贊同,因為redux真的提供了各種豐富的中間,方便我們使用,那麼應用這些中介軟體,就需要applyMiddleware來實現了。

我們來看看:

...

const middlewares = compose(applyMiddleware(sagaMiddleware, thunk, logger), autoRehydrate());

const store = createStore(reducers, undefined, middlewares);
...

上面主要應用了三個中介軟體,thunk, saga, log.

下面我們會依次講解。

常用中介軟體

redux的中間真的很多,但是本人沒有一一嘗試,對於在專案中我比較常用的,這裡和大家分享一下。

react-thunk分析

這個中介軟體在網上會看到很多資料,說的很高大上,最開始我也雲裡霧裡,但是究其根本,用它就一個好處: 方便在action中接收dispatch和getState兩個引數,也就是我們不需要在觸發action時候傳遞這兩個引數,我們就能獲取到。

主要是因為react-thunk會在非同步處理中預設傳過來,以便於我們在action中進一步dispatch其他的操作。

看一下程式碼:

/**
 * Created by Richard on 12/20/16.
 */
import { createAction } from 'redux-actions';
import { GET_CONTACTS } from './constants';
import { SAVE_DATA } from './constants';
import fetch from 'isomorphic-fetch';

export const getContacts = createAction(GET_CONTACTS);

export const saveData = createAction(SAVE_DATA);

export const getData = () => (dispatch, getState) => {
  fetch('http://offline-news-api.herokuapp.com/stories')
    .then(function(response) {
      if (response.status >= 400) {
        throw new Error("Bad response from server");
      }
      return response.json();
    })
    .then(function(stories) {
      console.log(stories);
      dispatch(getContacts(stories));
    });
}

reselect分析

我認為這個reselect其實算不上redux的中介軟體,因為他不來源於redux。但是這個外掛和redux配合使用,在專案中的確帶來很多好處。

reselect主要用於分析處理reducer傳遞過來的state, 並且判斷當前的state和上一個state是否為同一個,同一個即不重新整理頁面,在一定程度上有助於提高效率。

而且在進一步處理state的業務邏輯上, 也提供了一些action,可以方便的處理不同模組下的state關係。

看一下程式碼:

/**
 * Created by Richard on 1/11/17.
 */
import { createSelector } from 'reselect';

export const getAllItems = createSelector(
    [
            state => state.word.getJokesList,
    ],
    (items) => {
            return items;
    }
);

還有很多語法,需要大家自己摸索一下啦,很好用。

redux-actions分析

redux-actions這個顧名思義就是集中處理所有action的,方便使用,即簡化了程式碼,主要會應用到action和reducer中,在action中建立,在reducer中接收。

我們看一下程式碼:

/**
 * Created by Richard on 12/30/16.
 */

import { createAction } from 'redux-actions';

import * as types from './word-constants';

export const successFetchData = createAction(types.SUCCESS_FETCH_DATA);

/**
 * Created by Richard on 12/29/16.
 */

import { handleActions } from 'redux-actions';
import * as types from './word-constants';
import { combineReducers } from 'redux';


const getJokesList = handleActions({
        [types.SUCCESS_FETCH_DATA]: (state, action) => {
                state = action.payload;
                console.log(action.payload);
                return [...state];
        }
}, []);

export default combineReducers({getJokesList});

程式碼中,我們用createAction建立一個action,以便省略了type引數,與此同時,會自動生一個一個payload引數用於傳遞資料到reducer中。

同樣在reducer中我們可以使用handleAction接收對應的action。

redux-saga分析

對於中型專案來講,我們需要處理很多業務邏輯,因為js沒有多執行緒而言(排除webworker). 大多數都是非同步回撥處理,所以複雜的非同步多少讓你的程式碼雜亂,redux-saga主要作用在於處理各種複雜的非同步操作,從而減少程式碼量,簡化action的操作。

看一下程式碼:

/**
 * Created by Richard on 1/11/17.
 */
import { call, put, take, select } from 'redux-saga/effects';
import { get, getPicturesUrl } from '../../../utils/api';
import { successFetchPictureData } from './picture-list-actions';
import * as types from './picture-list-constants';

export default function* pictureFlow() {
        try {
                yield take(types.START_FETH_PICTURE);
                const data = yield call(get, getPicturesUrl());
                yield put(successFetchPictureData(data));
        } catch (e){

        }
}

對於saga的更多資訊,歡迎大家閱讀我寫的saga應用一篇文章。

總結

單對Redux而言,每一個框架都是一個故事,都值得我們仔細品味,無論從程式碼簡化上,還是後期維護上,都起著至關重要的作用,弄清楚每個框架的功能和作用,才能更好的在架構中加以設計。

這裡寫圖片描述