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