1. 程式人生 > >redux-devtools攻略

redux-devtools攻略

Walkthrough(攻略)

原文包含程式碼在: https://github.com/94dreamer/Note/tree/master/redux-devtools

Browser Extension(瀏覽器擴充套件)

如果你不想安裝redux devtools整合到我們的專案程式碼中,我們可以使用Redux DevTools Extension擴充套件工具在chrome瀏覽或者是火狐瀏覽器上安裝。這個瀏覽器擴充套件工具提供了許多流行的監視,非常容易配置來過濾actions,並且它還不需要install任何的包。

Manual Integration(手動整合)

如果你想要完全控制devtools在哪裡顯示,或者開發自定義的監控,你可能會有手動配置的需求。雖然要多了一些步驟,但是你將完全控制監視器和它們的配置項。

Installation(安裝)

npm install --save-dev redux-devtools 你可能同時也想安裝一些監視器: npm install --save-dev redux-devtools-log-monitor npm install --save-dev redux-devtools-dock-monitor

Usage(使用)

Create a DevTools Component(建立一個DevlTools元件) 在你的專案中,通過一個monitor元素來建立一個DevTools元件,我們可以看一看下面例子中我們的monitor將由LogMonitor 合併 DockMonitor組成:

containers/DevTools.js
import React from 'react';

// 從redux-devtools中引入
import { createDevTools } from 'redux-devtools';

// Monitors是單獨的包,我們也可以自己定義一個
import LogMonitor from 'redux-devtools-log-monitor';
import DockMonitor from 'redux-devtools-dock-monitor';

// createDevTools 通過一個監視器和產生器來建立一個DevTools component
const DevTools = createDevTools(
  // Monitors 是一個個單獨的props.
  // 查詢這些包的github地址來學習瞭解他們的props.
  // 這裡,我們把LogMonitor放在DockMonitor裡.
  // 注意: DockMonitor預設是可見的.
  <DockMonitor toggleVisibilityKey='ctrl-h'
               changePositionKey='ctrl-q'
               defaultIsVisible={true}>
    <LogMonitor theme='tomorrow' />
  </DockMonitor>
);

export default DevTools;

注意你現在可以直接使用 LogMonitor 安放你應用的UI內而不需要嵌在 DockMonitor裡。

// 如果你的確不想使用dockingUI, 直接使用 <LogMonitor>
const DevTools = createDevTools(
  <LogMonitor theme='solarized' />
);

Use DevTools.instrument() Store Enhancer(Store增強版)

我們通過createDevTools()建立的DevTools元件有一個特殊的靜態方法,叫做instrument().它返回一個store的增強版store enhancer ,我們需要在開發環境中使用。

store enhancer是一個函式,提高了createStore()的行為。你可以把store enhancer作為最後一個引數傳遞給 createStore()。你可能已經使用了另一個store enhancer—applyMiddleware()。不像applyMiddleware(),你需要關心的只有如何使用DevTools.instrument()在開發環境中,不在生產環境中。

最簡單的辦法是使用 compose()函式來聯絡幾個store enhancers。比如這樣:compose(applyMiddleware(m1, m2, m3), DevTools.instrument())。

你可以給它新增額外的引數:DevTools.instrument({ maxAge: 50, shouldCatchErrors: true })。可以看redux-devtools-instrument's API 獲取更多的細節。

你應該新增DevTools.instrument()在applyMiddleware後面在你的compose函式參內,這是很關鍵的。這是因為applyMiddleware 可能是非同步的,但是 DevTools.instrument() 期望所有的action都是一個普通的物件而不是非同步中介軟體比如 redux-promis或者redux-thunk所解釋的。所以確保中介軟體 applyMiddleware放在compose引數的第一位,DevTools.instrument()緊隨其後。

store/configureStore.js
import { createStore, applyMiddleware, compose } from 'redux';
import rootReducer from '../reducers';
import DevTools from '../containers/DevTools';

const enhancer = compose(
  // 你想在開發環境使用的Middleware:
  applyMiddleware(d1, d2, d3),
  // 這是必需的! 使用你選擇的附帶monitors的Redux DevTools
  DevTools.instrument()
);

export default function configureStore(initialState) {
  // 注意: 只有Redux >= 3.1.0 才支援enhancer作為第三個引數.
  // 可以看 https://github.com/rackt/redux/releases/tag/v3.1.0
  const store = createStore(rootReducer, initialState, enhancer);

  // 熱過載reducers (requires Webpack or Browserify HMR to be enabled)
  if (module.hot) {
    module.hot.accept('../reducers', () =>
      store.replaceReducer(require('../reducers')/*.default if you use Babel 6+ */)
    );
  }

  return store;
}

如果你喜歡,你可以新增另一個叫persistState()。它可以讓你把控整體的會話(包括全部的dispatch出來的action和監聽的狀態),只需要一個URL的引數。你可以訪問http://localhost:3000/?debug_session=reproducing_weird_bug ,在應用中操作,然後開啟http://localhost:3000/?debug_session=some_other_feature ,最後返回到http://localhost:3000/?debug_session=reproducing_weird_bug ,狀態將會被清空重置。如果你喜歡它,你可以把它加入到你的專案當中,這也是一個頗具成就兼備靈感的做法。

Exclude DevTools from Production Builds(在生產環境中排出DevTools)

最後,我們需要確保我們的DevlTools程式碼沒有被包含進生產環境程式碼。我們可以使用一些Webpack的DefinePlugin外掛,或者是Browserify的envify。

祕訣是用過設定process.env.NODE_ENV 來控制我們的環境設定,比如說我們的redux-devtools 僅在我們的 process.env.NODE_ENV 為空或者不是’production’執行。

一般來說,如果使用Webpack你需要兩個配置檔案,一個針對開發環境一個針對生產環境,這是一個列子:

webpack.config.prod.js

// ...
plugins: [
  new webpack.DefinePlugin({
    'process.env.NODE_ENV': JSON.stringify('production')
  })
],
// ...

如果你正在使用Webpack和Bable的ES6模組系統,你應該試著通過判斷process.env.NODE_ENV來決定是否import包含這個DevTools到我們的打包檔案中。 然而ES6語法禁止這樣,導致不會編譯成功。恰好,我們可以通過CommonJS規範的require來代替。Babel會將它編譯,並在Webpack打包之前決定是否包含。 這就是為什麼我們要建立一個configureStore.js檔案,我們使用configureStore.dev.js 或者 configureStore.prod.js取決於我們的配置。 雖然我們為此付出了稍多的維護代價,但好處是,我們可以完全掌控住任何開發依賴不會放進我們的生產程式碼中,並且我們可以更靈活地使用不用的中介軟體(比如 崩潰報告、日誌記錄)在我們的生產環境中。

store/configureStore.js

// 使用DefinePlugin (Webpack) 或者 loose-envify (Browserify)
// 把開發和生產環境區分開發打包
if (process.env.NODE_ENV === 'production') {
  module.exports = require('./configureStore.prod');
} else {
  module.exports = require('./configureStore.dev');
}
store/configureStore.prod.js
import { createStore, applyMiddleware, compose } from 'redux';
import rootReducer from '../reducers';

// 你想在生產環境使用的中介軟體:
const enhancer = applyMiddleware(p1, p2, p3);

export default function configureStore(initialState) {
    // 注意: 只有Redux >= 3.1.0 才支援enhancer作為第三個引數.
// 可以看 https://github.com/rackt/redux/releases/tag/v3.1.0
return createStore(rootReducer, initialState, enhancer);
};

store/configureStore.dev.js

import { createStore, applyMiddleware, compose } from 'redux';
import { persistState } from 'redux-devtools';
import rootReducer from '../reducers';
import DevTools from '../containers/DevTools';

const enhancer = compose(
  //你想在開發環境使用的Middleware:
  applyMiddleware(d1, d2, d3),
  //這是必需的! 使用你選擇的附帶monitors的Redux DevTools
  DevTools.instrument(),
  //引數,讓你輸入?debug_session=<key> 在位址列中持續地debug會話
  persistState(getDebugSessionKey())
);

function getDebugSessionKey() {
  //你可以編寫自定義的邏輯
  //預設情況下我們是這樣輸入在位址列中的 ?debug_session=<key>
  const matches = window.location.href.match(/[?&]debug_session=([^&]+)\b/);
  return (matches && matches.length > 0)? matches[1] : null;
}

export default function configureStore(initialState) {
  // 注意: 只有Redux >= 3.1.0 才支援enhancer作為第三個引數.
  // 可以看 https://github.com/rackt/redux/releases/tag/v3.1.0
  const store = createStore(rootReducer, initialState, enhancer);

  // 熱過載reducers (requires Webpack or Browserify HMR to be enabled)
  if (module.hot) {
    module.hot.accept('../reducers', () =>
      store.replaceReducer(require('../reducers')/*.default if you use Babel 6+ */)
    );
  }

  return store;
}

Render 在你的應用... 最後,引入DevTools 元件到你的頁面。 你可以把它放到index.js 裡面渲染。

index.js
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import configureStore from './store/configureStore';
import TodoApp from './containers/TodoApp';

// 不要這樣做,你把DevTools帶到了生產環境的bundle.
import DevTools from './containers/DevTools';

const store = configureStore();

render(
  <Provider store={store}>
    <div>
      <TodoApp />
      <DevTools />
    </div>
  </Provider>
  document.getElementById('app')
);

我們推薦使用一種類似上面configureStore.js的做法。建立一個root.js元件,來渲染我們應用的根節點(通常來說是一包含一些元件)。然後根據判斷process.env.NODE_ENV來判斷開發和生產版本暴露的js檔案。 containers/Root.js if (process.env.NODE_ENV === 'production') { module.exports = require('./Root.prod'); } else { module.exports = require('./Root.dev'); } containers/Root.dev.js import React, { Component } from 'react'; import { Provider } from 'react-redux'; import TodoApp from './TodoApp'; import DevTools from './DevTools';

export default class Root extends Component {
  render() {
    const { store } = this.props;
    return (
      <Provider store={store}>
        <div>
          <TodoApp />
          <DevTools />
        </div>
      </Provider>
    );
  }
}
containers/Root.prod.js
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import TodoApp from './TodoApp';

export default class Root extends Component {
  render() {
    const { store } = this.props;
    return (
      <Provider store={store}>
        <TodoApp />
      </Provider>
    );
  }
}

Gotchas(坑)

你的reducers必須是一個純淨無副作用的純函式. 例如,即使在reducer中使用了一個隨機的random的ID來標識某個內容,它也會使其不純淨。這樣的操作我們一般放在action的建立中。

確保DevTools.instrument()和render 只在開發環境中使用! 在生產中使用,它將會導致我們的應用變得非常緩慢,因為actions會源源不斷地積累。如上所述,你要根據判斷條件來引入它,比如DefinePlugin(Webpack)或者loos-envify(Browserify)來判斷不再打包程式碼時引入它。

這裡是一個Redux DevTools處理生產情況下一個極佳的(例子)[https://github.com/erikras/react-redux-universal-hot-example/].

DevTools.instrument()store增強器應該被新增到你的中介軟體的後面,然後被compose函式當作引數包含起來,因為中介軟體可能是非同步的.否則DevTools將不能觀察到通過非同步中介軟體(比如redux-promise或者redux-thunk)的action。

What Next?(下一步)

現在你可以看到DevTools了,你可能想要學習這些按鈕的意思並且使用它們。這一切通常取決於monitor(監視器)。 你可以開始探索關於 LogMonitor 和 DockMonitor 的文件,我們預設一起使用它們。我們就可以自定義更多自己要得顯示監聽內容。

原文:http://www.94dreamer.com/index.php/Home/Article/index/id/57