dva源碼解析(三)

 

轉載   原文 https://blog.csdn.net/zhangrui_web/article/details/79651448html

API

輸出文件

dva

默認輸出文件。node

dva/router

默認輸出 react-router 接口, react-router-redux 的接口經過屬性 routerRedux 輸出。react

好比:git

import { Router, Route, routerRedux } from 'dva/router';

dva/fetch

異步請求庫,輸出 isomorphic-fetch 的接口。不和 dva 強綁定,能夠選擇任意的請求庫。github

dva/saga

輸出 redux-saga 的接口,主要用於用例的編寫。(用例中須要用到 effects)web

dva/dynamic

解決組件動態加載問題的 util 方法。redux

好比:react-native

import dynamic from 'dva/dynamic'; const UserPageComponent = dynamic({ app, models: () => [ import('./models/users'), ], component: () => import('./routes/UserPage'), });

opts 包含:數組

  • app: dva 實例,加載 models 時須要
  • models: 返回 Promise 數組的函數,Promise 返回 dva model
  • component:返回 Promise 的函數,Promise 返回 React Component

dva API

app = dva(opts)

建立應用,返回 dva 實例。(注:dva 支持多實例)服務器

opts 包含:

  • history:指定給路由用的 history,默認是 hashHistory
  • initialState:指定初始數據,優先級高於 model 中的 state,默認是 {}

若是要配置 history 爲 browserHistory,能夠這樣:

import createHistory from 'history/createBrowserHistory'; const app = dva({ history: createHistory(), });

另外,出於易用性的考慮,opts 裏也能夠配全部的 hooks ,下面包含所有的可配屬性:

const app = dva({ history, initialState, onError, onAction, onStateChange, onReducer, onEffect, onHmr, extraReducers, extraEnhancers, });

app.use(hooks)

配置 hooks 或者註冊插件。(插件最終返回的是 hooks )

好比註冊 dva-loading 插件的例子:

import createLoading from 'dva-loading'; ... app.use(createLoading(opts));

hooks 包含:

onError((err, dispatch) => {})

effect 執行錯誤或 subscription 經過 done 主動拋錯時觸發,可用於管理全局出錯狀態。

注意:subscription 並無加 try...catch,因此有錯誤時需經過第二個參數 done 主動拋錯。例子:

app.model({ subscriptions: { setup({ dispatch }, done) { done(e); }, }, });

若是咱們用 antd,那麼最簡單的全局錯誤處理一般會這麼作:

import { message } from 'antd'; const app = dva({ onError(e) { message.error(e.message, /* duration */3); }, });

onAction(fn | fn[])

在 action 被 dispatch 時觸發,用於註冊 redux 中間件。支持函數或函數數組格式。

例如咱們要經過 redux-logger 打印日誌:

import createLogger from 'redux-logger'; const app = dva({ onAction: createLogger(opts), });

onStateChange(fn)

state 改變時觸發,可用於同步 state 到 localStorage,服務器端等。

onReducer(fn)

封裝 reducer 執行。好比藉助 redux-undo 實現 redo/undo :

import undoable from 'redux-undo'; const app = dva({ onReducer: reducer => { return (state, action) => { const undoOpts = {}; const newState = undoable(reducer, undoOpts)(state, action); // 因爲 dva 同步了 routing 數據,因此須要把這部分還原 return { ...newState, routing: newState.present.routing }; }, }, });

詳見 examples/count-undo 。

onEffect(fn)

封裝 effect 執行。好比 dva-loading 基於此實現了自動處理 loading 狀態。

onHmr(fn)

熱替換相關,目前用於 babel-plugin-dva-hmr 。

extraReducers

指定額外的 reducer,好比 redux-form 須要指定額外的 form reducer:

import { reducer as formReducer } from 'redux-form' const app = dva({ extraReducers: { form: formReducer, }, });

extraEnhancers

指定額外的 StoreEnhancer ,好比結合 redux-persist 的使用:

import { persistStore, autoRehydrate } from 'redux-persist'; const app = dva({ extraEnhancers: [autoRehydrate()], }); persistStore(app._store);

app.model(model)

註冊 model,詳見 #Model 部分。

app.unmodel(namespace)

取消 model 註冊,清理 reducers, effects 和 subscriptions。subscription 若是沒有返回 unlisten 函數,使用 app.unmodel 會給予警告⚠️。

app.router(({ history, app }) => RouterConfig)

註冊路由表。

一般是這樣的:

import { Router, Route } from 'dva/router'; app.router(({ history }) => { return ( <Router history={history}> <Route path="/" component={App} /> <Router> ); });

推薦把路由信息抽成一個單獨的文件,這樣結合 babel-plugin-dva-hmr 可實現路由和組件的熱加載,好比:

app.router(require('./router'));

而有些場景可能不使用路由,好比多頁應用,因此也能夠傳入返回 JSX 元素的函數。好比:

app.router(() => <App />);

app.start(selector?)

啓動應用。selector 可選,若是沒有 selector 參數,會返回一個返回 JSX 元素的函數。

app.start('#root');

那麼何時不加 selector?常見場景有測試、node 端、react-native 和 i18n 國際化支持。

好比經過 react-intl 支持國際化的例子:

import { IntlProvider } from 'react-intl'; ... const App = app.start(); ReactDOM.render(<IntlProvider><App /></IntlProvider>, htmlElement);

Model

model 是 dva 中最重要的概念。如下是典型的例子:

app.model({ namespace: 'todo', state: [], reducers: { add(state, { payload: todo }) { // 保存數據到 state return [...state, todo]; }, }, effects: { *save({ payload: todo }, { put, call }) { // 調用 saveTodoToServer,成功後觸發 `add` action 保存到 state yield call(saveTodoToServer, todo); yield put({ type: 'add', payload: todo }); }, }, subscriptions: { setup({ history, dispatch }) { // 監聽 history 變化,當進入 `/` 時觸發 `load` action return history.listen(({ pathname }) => { if (pathname === '/') { dispatch({ type: 'load' }); } }); }, }, });

model 包含 5 個屬性:

namespace

model 的命名空間,同時也是他在全局 state 上的屬性,只能用字符串,不支持經過 . 的方式建立多層命名空間。

state

初始值,優先級低於傳給 dva() 的 opts.initialState

好比:

  1.  
    const app = dva({
  2.  
    initialState: { count: 1 },
  3.  
    });
  4.  
    app.model({
  5.  
    namespace: 'count',
  6.  
    state: 0,
  7.  
    });

此時,在 app.start() 後 state.count 爲 1 。

reducers

以 key/value 格式定義 reducer。用於處理同步操做,惟一能夠修改 state 的地方。由 action 觸發。

格式爲 (state, action) => newState 或 [(state, action) => newState, enhancer]

詳見: https://github.com/dvajs/dva/blob/master/packages/dva-core/test/reducers-test.js

effects

以 key/value 格式定義 effect。用於處理異步操做和業務邏輯,不直接修改 state。由 action 觸發,能夠觸發 action,能夠和服務器交互,能夠獲取全局 state 的數據等等。

格式爲 *(action, effects) => void 或 [*(action, effects) => void, { type }]

type 類型有:

  • takeEvery
  • takeLatest
  • throttle
  • watcher

詳見:https://github.com/dvajs/dva/blob/master/packages/dva-core/test/effects-test.js

subscriptions

以 key/value 格式定義 subscription。subscription 是訂閱,用於訂閱一個數據源,而後根據須要 dispatch 相應的 action。在 app.start() 時被執行,數據源能夠是當前的時間、服務器的 websocket 鏈接、keyboard 輸入、geolocation 變化、history 路由變化等等。

格式爲 ({ dispatch, history }, done) => unlistenFunction

注意:若是要使用 app.unmodel(),subscription 必須返回 unlisten 方法,用於取消數據訂閱。

相關文章
相關標籤/搜索