react+redux教程(四)undo、devtools、router

來源:互聯網
上載者:User

標籤:

上節課,我們介紹了一些es6的新文法:react+redux教程(三)reduce()、filter()、map()、some()、every()、...展開屬性

今天我們通過解讀redux-undo的官方範例程式碼來學習,在redux中使用撤銷功能、devtools功能、以及router。

例子

這個例子是個計數器程式,包含計數器、右邊的redux開發工具、還有一個路由(不過只有“/”這一個地址)。

原始碼:

https://github.com/lewis617/myReact/tree/master/redux-undo-boilerplate

 撤銷

實現撤銷功能非常簡單,你只需要使你的reducers可以撤銷就可以了。這是什麼意思呢?看代碼

reducers/index.js

 

import { combineReducers } from ‘redux‘import counter from ‘./counter‘import {  INCREMENT_COUNTER, DECREMENT_COUNTER,  UNDO_COUNTER, REDO_COUNTER} from ‘../actions/counter‘import undoable, { includeAction } from ‘redux-undo‘const rootReducer = combineReducers({  counter: undoable(counter, {    filter: includeAction([INCREMENT_COUNTER, DECREMENT_COUNTER]),    limit: 10,    debug: true,    undoType: UNDO_COUNTER,    redoType: REDO_COUNTER  })})export default rootReducer

我們使用redux-undo這個包給我們提供的undoable和includeAction,就可以可以給指定reducer(counter)添加撤銷功能。filter是選擇過濾的action有哪些,這裡我們只撤銷重做加減action,也就是INCREMENT_COUNTER, DECREMENT_COUNTER,
limit是次數限制,debug是是否調試碼,undotype和redotype是撤銷重做的action。

如此以來,我只需要觸發撤銷重做的action便可以實現撤銷重做功能,就是這麼簡單!

devtools

接下來,我們開始學習使用devtools這個功能,devtools是什嗎?devtools的實質其實也是組件。devtools能幹什嗎?devtools可以協助我們看到整個程式的狀態和整個程式的觸發的action的日誌記錄。我們如何安裝devtools呢?首先,我們知道devtools是個組件,那麼我們直接把devtools放在容器中渲染出來不就可以了嗎?

containers/DevTools.js

/*eslint-disable*/import React from ‘react‘import { createDevTools } from ‘redux-devtools‘import LogMonitor from ‘redux-devtools-log-monitor‘import DockMonitor from ‘redux-devtools-dock-monitor‘/*eslint-enable*/export default createDevTools(  <DockMonitor toggleVisibilityKey="H"               changePositionKey="Q">    <LogMonitor />  </DockMonitor>)

這是一個可以複用的容器代碼,也就意味著,你可以直接把這個js檔案,複製粘貼到你的項目中。這段代碼我們輸出了一個devtools組件。

containers/Root.js

/* global __DEVTOOLS__ *//*eslint-disable*/import React, { Component, PropTypes } from ‘react‘import { Provider } from ‘react-redux‘import { Router } from ‘react-router‘import configureStore from ‘../store/configureStore‘import routes from ‘../routes‘/*eslint-enable*/const store = configureStore()function createElements (history) {  const elements = [    <Router key="router" history={history} children={routes} />  ]  if (typeof __DEVTOOLS__ !== ‘undefined‘ && __DEVTOOLS__) {    /*eslint-disable*/    const DevTools = require(‘./DevTools‘)    /*eslint-enable*/    elements.push(<DevTools key="devtools" />)  }  return elements}export default class Root extends Component {  static propTypes = {    history: PropTypes.object.isRequired  }  render () {    return (      <Provider store={store} key="provider">        <div>          {createElements(this.props.history)}        </div>      </Provider>    )  }}

這段代碼,我們將我們匯出的devtools組件放在了router這個組件的下面,不過我們加了一個typeof __DEVTOOLS__ !== ‘undefined‘ && __DEVTOOLS__的判斷,如果條件成立,我們將渲染devtools,否則不渲染。這樣做,意味著我們可以通過參數控制devtools在開發環境中顯示,在生產環境中不顯示。

是不是渲染出來,就可以了?當然不是!我們還需要在store裡面註冊!

store/configureStore.js

 

/* global __DEVTOOLS__ */import { createStore, applyMiddleware, compose } from ‘redux‘// reducerimport rootReducer from ‘../reducers‘// middlewareimport thunkMiddleware from ‘redux-thunk‘import promiseMiddleware from ‘redux-promise‘import createLogger from ‘redux-logger‘const loggerMiddleware = createLogger({  level: ‘info‘,  collapsed: true})const enforceImmutableMiddleware = require(‘redux-immutable-state-invariant‘)()let createStoreWithMiddlewareif (typeof __DEVTOOLS__ !== ‘undefined‘ && __DEVTOOLS__) {  const { persistState } = require(‘redux-devtools‘)  const DevTools = require(‘../containers/DevTools‘)  createStoreWithMiddleware = compose(    applyMiddleware(      enforceImmutableMiddleware,      thunkMiddleware,      promiseMiddleware,      loggerMiddleware    ),    DevTools.instrument(),    persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/))  )(createStore)} else {  createStoreWithMiddleware = compose(    applyMiddleware(thunkMiddleware, promiseMiddleware)  )(createStore)}/** * Creates a preconfigured store. */export default function configureStore (initialState) {  const store = createStoreWithMiddleware(rootReducer, initialState)  if (module.hot) {    // Enable Webpack hot module replacement for reducers    module.hot.accept(‘../reducers‘, () => {      const nextRootReducer = require(‘../reducers/index‘)      store.replaceReducer(nextRootReducer)    })  }  return store}

 


到此為止,devtools我們就安裝好了,就是這麼簡單!把它渲染出來就可以了,可以放在整個程式的下面就可以了!

store enhancer

DevTools.instrument() 這行代碼使得devtools可以使用了!有的同學會問,這個instrument()是什麼鬼?官方稱之為store enhancer,翻譯過來就是store加強器,跟applymiddleware是一類,都是store加強器。那麼store加強器,能幹什嗎?store加強器可以重新構建一個更牛逼的store,來替換之前的基礎版的store,讓你的程式可以增加很多別的功能,比如appllymiddleware可以給你的redux增加中介軟體,使之可以擁有非同步功能,日誌功能等!

 

enforceImmutableMiddleware,thunkMiddleware, promiseMiddleware, loggerMiddleware

 

有的同學會問,enforceImmutableMiddleware是什嗎?幹嘛用的?這個使用禁止你改變state的。什嗎?不改變state,我們如何更新狀態,redux不允許你改變state,在reducer中我們必須要返回一個新的state,而不是修改原來的state!

那個thunk是什嗎?thunk我們已經在react+redux教程(一)connect、applyMiddleware、thunk、webpackHotMiddleware裡面講過了。

那麼什麼是promiseMiddleware?這也是個中介軟體,和thunk一樣,使得你的action可以具備非同步功能。不過,我們可以發現,本例中我們並沒有用到thunk和promiseMiddleware這兩個中介軟體,本例子是個種子檔案,可以在這個基礎上拓展,所以作者提前寫好了兩個常用中介軟體,便於我們日後使用!

那麼loggerMiddleware是用來幹嘛的?顧名思義,就是用來記錄日誌的,當你添加這個中介軟體,你可以在命令列中看到相關的列印日誌!當然你可以在運行程式的時候,去掉這個中介軟體,來對比觀察它的作用!

 

instrument()與compose()寫法

instrument()不同於applymiddleware,它只能用於開發環境,只能enable你的devtools組件!那麼我們把applymiddleware和instrument用逗號隔開,為什嗎?這是compose寫法,用來代替以前的函數嵌套!

 

router

簡單來說,router也是個組件,一個多重視圖的組件,這個組件可以通過切換url來切換視圖,總之它還是個組件。既然是組件,我們只要把它渲染出來就可以了!

最頂層我們要渲染一個Router   ,代碼在containers/Root.js中,我們就不重複列出代碼清單了。

然後我們開始渲染各個視圖,這裡我們只有一個視圖,也就是目錄是“/”的視圖,我們把它渲染出來!

routes.js

 

/*eslint-disable*/import React from ‘react‘import { Route } from ‘react-router‘import App from ‘./containers/App‘import * as containers from ‘./containers‘/*eslint-enable*/const {  CounterPage} = containersexport default (  <Route component={App}>    <Route path="/" component={CounterPage} />  </Route>)

 

我們匯出了一個視圖,這個視圖的組件是CounterPage。就是這麼簡單!

然後,我們在containers/Root.js,將它渲染到Router組件裡面就可以了!

 

<Router key="router" history={history} children={routes} />

 

我們可以發現,我們並沒有把devtools這個組件放在路由群組件裡面。這意味著,無論你如何切換視圖,devtools都一直會渲染出來!

當然react-router的api還有很多,我們只是用了很少一部分,我不建議專門閱讀api文檔,應該在項目中,遇到不會的查詢api文檔,這樣對api的用法的理解會更加的深刻!

 

react+redux教程(四)undo、devtools、router

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.