iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 24
1
Modern Web

寫React的那些事系列 第 24

React Day24 - Middleware運用 與 Logger for Redux

  • 分享至 

  • xImage
  •  

上一篇我們介紹milddleware的概念,因為篇幅實在很長,還沒有講到實際上如何把它運用到我們的store裡面,現在讓我們簡單的來把logger加入到store中!

Middleware運用


首先,先把昨天的logger加入到 index.js

const logger = store => next => action => {
  console.log('dispatching', action);
  let result = next(action);
  console.log('next state', store.getState());
  return result;
};

再使用applyMiddleware,把自製的middlewares加入createStore:

import { createStore, applyMiddleware } from 'redux';
import todoApp from './reducers';

let store = createStore(
  todoApp,
  // applyMiddleware() 告訴 createStore() 如何處理 middleware
  applyMiddleware(logger)
);

完整的 index.js ,如下:

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';

import todoApp from './reducers';
import TodoAppContainer from './containers/TodoAppContainer';

const logger = store => next => action => {
  console.log('dispatching', action);
  let result = next(action);
  console.log('next state', store.getState());
  return result;
};

let store = createStore(
  todoApp,
  applyMiddleware(logger)
);

ReactDOM.render(
  <Provider store={store}>
    <TodoAppContainer />
  </Provider>,
  document.getElementById('main')
);

現在只要我們有發送任何的action,都可以在console中看到action和next state,自製logger middleware就已經完成囉!不過,其實我們可以用另一套已經寫好的Logger for Redux來達成這個功能。

Logger for Redux


首先也是透過npm來安裝:

npm install redux-logger --save

透過createLogger,建立redux-logger的middleware函式:

createLogger(options?: Object) => LoggerMiddleware

options

裡面可以建立一些options,options不是必填,但可以讓你客製化logger的形式,以下列出options及說明:

{
  level = 'log': 'log' | 'console' | 'warn' | 'error' | 'info', // console's level
  duration = false: Boolean, // 顯示action執行的時間
  timestamp = true: Boolean, // 顯示每個action timestamp
  colors: ColorsObject, // 設定console顏色配置
  logger = console: LoggerObject, // 自己定義log方法
  logErrors = true: Boolean, // 遇到錯誤會丟出錯誤訊息
  collapsed, // 是否把console訊息折疊,可是boolean或是一個傳回boolean的函式,函式可以接收getState和action兩個參數
  predicate, // 判斷是否記錄log
  stateTransformer, // 轉換state格式,例如使用Immutable object轉換成JSON
  actionTransformer, // 轉換action格式,例如使用Immutable object轉換成JSON
  errorTransformer, // 轉換error格式,例如object變成字串
  titleFormatter, // 轉換title格式,預設格式:action @ ${time} ${action.type} (in ${took.toFixed(2)} ms)
  diff = false: Boolean, // 顯示state有被改變的地方,diff出來改變的部分
  diffPredicate // 過濾要顯示diff的函式
}

把redux-logger加入store的方法,很簡單:

const logger = createLogger();
let store = createStore(
  todoApp,
  applyMiddleware(logger)
);

有一個地方需要特別注意的,當applyMiddleware傳入多個middlewares時,logger必須放在最後一個,這表示在dispatch後會先做log,而不會受到其他middleware影響。

Logger must be the last middleware in chain, otherwise it will log thunk and promise, not actual actions.

以下先假設加入另外兩個middleware,redux-thunk、redux-promise當作多個middleware範例:

import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import promise from 'redux-promise';
import createLogger from 'redux-logger';

const logger = createLogger();
const store = createStore(
  reducer,
  applyMiddleware(thunk, promise, logger)
);

當你透過 npm run dev 的時候,可以在console清楚地看到actions的動作都被記錄下來,可以透過比對prev state、next state和action內容來檢查,當程式有error時,很容易可以找出到底是哪邊的問題。

只在開發環境log

通常我們只會在開發環境時才有log顯示,不讓資訊直接出現在console中,所以我們會在建立store的時候判斷現在的環境:

const middlewares = [];
// 用process.env.NODE_ENV來判斷
if (process.env.NODE_ENV === 'development') {
  // options設定執行時間
  const logger = createLogger({ duration:true });
  middlewares.push(logger);
}

let store = createStore(
  todoApp,
  applyMiddleware(...middlewares)
);

但是process.env.NODE_ENV是怎麼產生的呢?還記得我們Day10有提到的webpack plugins,裡面有一個 DefinePlugin 可以讓我們設定變數傳入嗎?

所以我們要在 webpack.config.js 裡面做設定,先不直接export webpack物件,改用一個變數webpackConfig把設定存起來,然後,用node的變數來判斷環境,依照不同環境指定變數:

// 這邊的process.env.NODE_ENV,是node.js的變數
if (process.env.NODE_ENV === 'production') {
  // 用DefinePlugin傳入process.env.NODE_ENV變數為production
  webpackConfig.plugins.push(
    new webpack.DefinePlugin({
      'process.env': { 'NODE_ENV': '"production"'}
    })
  );
} else {
  // 用DefinePlugin傳入process.env.NODE_ENV變數為development
  webpackConfig.plugins.push(
    new webpack.DefinePlugin({
      'process.env': { 'NODE_ENV': '"development"'}
    })
  );
}

最後,我們在 package.json 的script中指定process.env.NODE_ENV變數,只需指定NODE_ENV:

"scripts": {
  "dev": "NODE_ENV=development node server.js",
  "prod": "NODE_ENV=production webpack --progress --color",
  "test": "echo \"Error: no test specified\" && exit 1"
}

如果是windows的環境需要加上set:

"scripts": {
  "dev": "set NODE_ENV=development node server.js",
  "prod": "set NODE_ENV=production webpack --progress --color",
  "test": "echo \"Error: no test specified\" && exit 1"
}

但如果是多人一起開發,可以使用cross-env的方式來跨平台的問題,當然使用vagrant一起開發就沒這個問題了!這邊提供練習時作參考。

今天的檔案已經放在Git 上,當執行開發環境時,會在console上看到log記錄囉!


上一篇
React Day23 - Middleware概念
下一篇
React Day25 - Async Action 與 redux-thunk
系列文
寫React的那些事31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言