iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 19
3
Modern Web

激戰 ReactJS 30天系列 第 19

【Day19】 見證奇蹟的時刻 - 實作Redux

學習要為自己負責
為什麼上一篇明明講完了 Redux 這裡又要再一次拿出來做呢?
因為看文字看過去
對他的概念和用意略懂略懂
但略懂還是不會用阿!
所以
臨時動議再追加一篇 Redux 與資料流
這篇的目的是要透過實作
真正搞懂 Redux 和單向資料流的運作模式!
那麼廢話不多說馬上開始:

Redux 實作大挑戰!!!

首先要先定義 Actions

// action types 
export const PLUS = 'PLUS';
export const MINUS = 'MINUS';

// action creators
export function add(){
    return {
        type : PLUS,
        num :1
    }
};
export function sub(){
    return{
        type : MINUS,
        num : 1
    }
};

在這邊我定義了兩個 Action
分別是addsub
與他們對應的是PLUSMINUS兩個 Action Type
這兩個字將會是判斷什麼行為應該被作用的關鍵
定義好行為的種類後
接下來要來建構處理者
也就是 Reducer

import { combineReducers } from 'redux';
import { PLUS, MINUS } from '../actions/action.js';

const initialData = {
    value : 0
}

function calculator(state = initialData, action){
    switch(action.type){
        case PLUS:
        console.log("++");
            return Object.assign({},state,{
                value : state.value + action.num
            });
        case MINUS:
        console.log("--");
            return Object.assign({},state,{
                value : state.value - action.num
            });
        default:
            return state;
    }
}

const calculatorApp = combineReducers({
    calculator
});

export default calculatorApp;

Reducer 需要知道有哪些 Action Type
所以我們要將PLUSMINUS引入
接著 Reducer 會是負責管理 Store 的人
在建立 Redux 唯一的 Store 時也會被用上
所以我們要在這邊定義好初始狀態資料
也就是initialData在做的事情
建構好 Store 的長相後
接下來的是核心重點
根據不同的 Action Type 要做出對應的行為
這裡用 Switch 來判斷接受到的 Action 是什麼
利用剛剛定義好的PLUSMINUS來判斷是接收到哪個行為
然後對狀態資料做處理
要注意到的是
Reducer 要避免更動到原始的狀態資料
採取的模式應該要是回傳一個新的狀態資料
另外
Reducer 有時候會因為 Action 為針對不同目的設計而有多個
這時我們需要透過combineReducers這個 API 來合併他們
好讓 Store 有個明確的 Reducer 可以對應
最後不要忘記要 export

好的 完成這兩個東西大概完成了實現資料流的一半
接著我們先來寫畫面的外觀
首先我們會需要一個入口根組件(Root Component):

import React from 'react';
import ReactDOM from 'react-dom';
import { connect } from 'react-redux'
import StateData from './components/containers/StateData.js';

const App = () => (
  <div>
      <StateData />
  </div>
)

這段程式碼裡面
<StateData />是一個Container Components
這個先放掉之後再說
App 這個組件的用意是作為根組件
讓其他的 DOM 節點從這個點開始發展
這樣才能有一個傳入口讓 Store 把資料透過結構樹傳遞到需要的節點位置
然後是我們的執行畫面:

import React,{ PropTypes } from 'react';
import ReactDOM from 'react-dom';


function StateBoard({value, onClickAdd, onClickSub}){
    return(
        <div>
            <h1>{value}</h1>
            <button onClick={() => onClickAdd()}>+1</button>
            <button onClick={() => onClickSub()}>-1</button>
        </div>
    );
}

export default StateBoard;

這段程式碼其實就是我們以往寫的組件
這是沒有攜帶狀態的組件寫法
在這裡有一個名詞叫做Presentational Components
指的就是這種單純接受 props 並且呈現資料的組件
另外
還有一個是Container Components

import { connect } from 'react-redux';
import StateBoard from '../StateBoard.jsx';
import { add, sub } from '../../actions/action.js';

const mapStateToProps = (state) => {
  return {
    value: state.calculator.value
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    onClickAdd: () => {
      dispatch(add());
    },
    onClickSub: () =>{
      dispatch(sub());
    }
  }
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(StateBoard);

Presentational Components不同
這個組件通常沒有畫面元素
取而代之的是關於要使用哪些資料以及要產生哪些行為
Container Components可以透過mapStateToProps函式選取需要用到的狀態資料
透過mapDispatchToProps傳遞互動函式的動作行為
connect這些需要的資訊給Presentational Components
以實現網頁的資料與行為呈現

當節點都準備就緒
最後我們要將網頁渲染出來

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import calculatorApp from './reducers/reducers.js';
import App from "./App.jsx";

import {
  add,
  sub
} from './actions/action.js';

let store = createStore(calculatorApp);
console.log(store);

ReactDOM.render(
    <Provider store = {store}>
        <App />
    </Provider>,
    document.getElementById("app")
);

這段程式碼主要是根據 Reducer 創建 Store
渲染並透過Provider將 Store 傳遞進 Root Component
讓整個架構建立起來
執行畫面:
https://ithelp.ithome.com.tw/upload/images/20180107/20107674WLXIdXOg9C.png

在我實際練習的過程中
其實有的時候真的會弄不清楚發生什麼事情
所以!
在這邊我決定另外記錄一個
Redux 資料流實作的整體架構
就用這一張圖結束今天的整份筆記。
https://ithelp.ithome.com.tw/upload/images/20180107/20107674dMhPxhba8W.png
實作資料流的過程中
真的很清楚的看見自己把功能、畫面還有資料的處理分得很清楚
當程式長大之後
用這樣的方式感覺真的能夠在管理上方便非常多
今日挑戰大成功!

參考資料

  1. tutorialspoint-ReactJS Tutorial
  2. React 官方文件

>>> 隊友任意門 <<<


Day19 end
by 瑞Ray 。:.゚ヽ(*´∀`)ノ゚.:。


上一篇
【Day18】Reducks? - Redux
下一篇
【Day20】 向左走向右走 - Router
系列文
激戰 ReactJS 30天31

尚未有邦友留言

立即登入留言