Redux 入門

傳播正能量發表於2016-10-31

1.什麼是Redux

管理Web應用全域性狀態的框架。

單頁面應用,顧名思義,和傳統專案的最明顯區別就是專案只有一個頁面,頁面有一個根元素,我們寫的每一個頁面是一個大的元件,前端接管路由來渲染不同的頁面元件。

隨著應用的複雜,前端需要儲存更多的state,包括快取的全域性資料,本地生成尚未持久化到伺服器的資料,也包括 UI 狀態,如啟用的路由,被選中的標籤,是否顯示載入動效或者分頁器等等。

如果是單純的資料快取 也沒什麼需要考慮的東西,放到記憶體就可以了, 重點是還要讓state和view有繫結的關係。state的變化能夠觸發view的變化。

在我們的專案中,沒有用redux之前,我們都是頁面元件管理state,出現以下需求的時候,寫起來就比較複雜

  • 某個元件的狀態,需要共享

  • 某個狀態需要在任何地方都可以拿到

  • 一個元件需要改變全域性狀態

  • 一個元件需要改變另一個元件的狀態

2.Redux的原則和設計思想

2.1 三大原則

  • 單一資料來源:整個應用的 state 被儲存在一棵 object tree 中,並且這個 object tree 只存在於唯一一個 store 中

  • State 是隻讀的:惟一改變 state 的方法就是觸發 action,action 是一個用於描述已發生事件的普通物件。

  • 使用純函式來執行修改: 為了描述 action 如何改變 state tree ,你需要編寫 reducers。只要是同樣的輸入,必定得到同樣的輸出。
    純函式是函數語言程式設計的概念,必須遵守以下一些約束。

不得改寫引數
不能呼叫系統 I/O 的API
不能呼叫Date.now()或者Math.random()等不純的方法,因為每次會得到不一樣的結果

2.2 設計思想:

(1)Web 應用是一個狀態機,檢視與狀態是一一對應的。

(2)所有的狀態,儲存在一個物件裡面。

3.Redux中的概念

3.1 Action

執行的動作,包括動作所需要的資料,改變store資料的唯一來源,一般是通過store.dispatch() 將 action 傳到 store。

Action 本質上是 JavaScript 普通物件。

flux-standard-action FSA標準

  • type,必須,string或者Symbol

  • payload,可選,執行action所需要的資料,任何型別

  • error,可選,標識這個action是否有錯誤,true or false

  • meta,可選,任何型別,payload之外的其他資料。

3.2 Reducer

根據action 做更新state的操作。

Action 只是描述了有事情發生了這一事實,並沒有指明應用如何更新 state。而這正是 reducer 要做的事情。

3.3 Store

Store就是儲存全域性state的容器,儲存三個常用的api

  • getState,獲取當前的state

  • subscribe,給store變化新增監聽函式

  • dispatch,用於接受action的方法,觸發reducer和監聽函式

3.4 單項資料流

使用者通過View,dispatch 相應的action,store呼叫reducer獲取最新的state,並觸發通過subscribe訂閱的監聽函式,監聽函式中我們通過store的getState方法獲取最新的state,更新view。
工作流程圖
image description)

4.應用例項

simpleredux/index.js

import {createStore} from `redux`;
 
export function createAction(type, payload) {
    return {
        type,
        payload
    }
}
const initialState = {
    time: new Date().getTime()
}
 
function reducer(state = initialState, action) {
    switch (action.type) {
        case `NOW_TIME`:
            return {
                ...state,
                time: action.payload
            }
        default:
            return state;
    }
}
 
let store;
export function getStore() {
    if(store) return store;
    return store = createStore(reducer);
}

TestRedux.js

`use strict`;
 
import React, { Component } from `react`;
 
import {
    StyleSheet,
    View,
    Text
} from `react-native`;
import MtButton from `@scfe/react-native-button`;
import {getStore, createAction} from `../../simpleredux/index`;
const store = getStore();
class TestRedux extends Component {
    constructor(props) {
        super(props);
        let state = store.getState();
        this.state = {
            time: state.time
        };
        store.subscribe(()=>{
            let state = store.getState();
            this.setState({
                time: state.time
            });
        });
    }
 
    _sendAction() {
        let action = createAction(`NOW_TIME`, new Date().getTime());
        store.dispatch(action);
    }
    render() {
        return (
            <View style={styles.container}>
                <Text>{this.state.time}
                </Text>
                <MtButton text="發出action" onPress={this._sendAction.bind(this)} />
            </View>
        );
    }
}
 
const styles = StyleSheet.create({
    container: {
        flex: 1,
        padding: 40
    }
});
 
export default TestRedux;

相關文章