apollo

apollo 是(shì)一(yī / yì /yí)個(gè)基于(yú) redux 和(hé / huò) redux-thunk 的(de)數據流解決方案,通過對 reactreduxreact-router 的(de)整合極大(dà)的(de)簡化了(le/liǎo)前端項目的(de)開發流程,緻力于(yú)快速構建大(dà)型的(de)高可用的(de)前端系統。

優勢

  • 兼容性:既能擔任移動端主力開發框架,還可以(yǐ)在(zài) PC 端支持主流浏覽器,最低兼容 IE8。

  • 頁面效果:與其它開發框架(如 Angular )相比,更專注于(yú) UI 層面的(de) react 頁面渲染速度更快,加載時(shí)間更短。成熟的(de) UI 體系也(yě)較容易制作出(chū)良好的(de)體驗。

  • 開發成本: apollo 集成開發框架帶來(lái)更低開發維護成本,成熟的(de)規範和(hé / huò)完善的(de)文檔能爲(wéi / wèi)項目組省時(shí)省力,衆多的(de)⼯具滿足開發過程中常見的(de)需求。上(shàng)手即用,方便又快捷。

  • 可複⽤用性:成熟的(de)組件化結構,可複用性強。項目之(zhī)間的(de)組件可以(yǐ)共享互通。

  • 擴展性:活躍的(de)開源社區,琳琅滿目的(de)項目,取之(zhī)即用,适應能力強,版本升級成本低。

核心概念

數據流向

數據的(de)改變一(yī / yì /yí)般是(shì)用戶交互行爲(wéi / wèi)或者浏覽器行爲(wéi / wèi)(如路由跳轉等)觸發的(de),在(zài)這(zhè)類事件發生時(shí)會通過 dispatch 發起一(yī / yì /yí)個(gè) Action,如果是(shì)同步行爲(wéi / wèi)會直接通過 Reducer 改變 State ,如果是(shì)異步行爲(wéi / wèi)會先觸發 Thunk 然後流向 Reducer 最終改變 State,因此在(zài) apollo 中,數據流向将嚴格遵循單向數據流的(de)理念,從而(ér)保證項目的(de)可維護性。

data_flow

Model 組成

State

State 表示 Model 的(de)狀态數據,通常表現爲(wéi / wèi)一(yī / yì /yí)個(gè) JavaScript 對象(當然它可以(yǐ)是(shì)任何值);操作的(de)時(shí)候每次都要(yào / yāo)當作不(bù)可變數據(immutable data)來(lái)對待,保證每次都是(shì)全新對象,沒有引用關系,這(zhè)樣才能保證 State 的(de)獨立性,便于(yú)測試和(hé / huò)追蹤變化。

在(zài) apollo 中,您可以(yǐ)通過 apollo 的(de)實例屬性 _store 獲取頂部 state 數據,但一(yī / yì /yí)般很少會用到(dào):

const app = createApollo();
console.log(app._store); // 頂部的(de) state 數據

Action

Action 是(shì)把數據從應用傳到(dào) Store 的(de)有效載荷。它是(shì) Store 數據的(de)唯一(yī / yì /yí)來(lái)源。一(yī / yì /yí)般來(lái)說(shuō)你會通過 store.dispatch()Action 傳到(dào) StoreAction 必須帶有 type 屬性指明具體的(de)行爲(wéi / wèi),其它字段可以(yǐ)自定義,如果要(yào / yāo)發起一(yī / yì /yí)個(gè) Action 需要(yào / yāo)使用 dispatch 函數;需要(yào / yāo)注意的(de)是(shì) dispatch 是(shì)在(zài)組件 connect Model以(yǐ)後,通過 props 傳入的(de)。

添加新 todo 任務的(de) Action 是(shì)這(zhè)樣的(de):

dispatch({
  type: 'add',
});

dispatch 函數

dispatch 是(shì)一(yī / yì /yí)個(gè)用于(yú)觸發 Action 的(de)函數,Action 是(shì)改變 State 的(de)唯一(yī / yì /yí)途徑,但是(shì)它隻描述了(le/liǎo)一(yī / yì /yí)個(gè)行爲(wéi / wèi),而(ér) dispatch 可以(yǐ)看作是(shì)觸發這(zhè)個(gè)行爲(wéi / wèi)的(de)方式,而(ér) Reducer 則是(shì)描述如何改變數據的(de)。

dispatch({
  type: 'user/add', // 如果在(zài) model 外調用,需要(yào / yāo)添加 namespace
  payload: {}, // 需要(yào / yāo)傳遞的(de)信息
});

Reducer

Reducer 指定了(le/liǎo)應用狀态的(de)變化如何響應 Action 并發送到(dào) Store 的(de),記住 Action 隻是(shì)描述了(le/liǎo)有事情發生了(le/liǎo)這(zhè)一(yī / yì /yí)事實,并沒有描述應用如何更新 State。需要(yào / yāo)注意的(de)是(shì) Reducer 必須是(shì)純函數,所以(yǐ)同樣的(de)輸入必然得到(dào)同樣的(de)輸出(chū),它們不(bù)應該産生任何副作用。

const todoApp = (state = initialState, action) => {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      })
    default:
      return state
  }
}

Thunk

Thunk 用于(yú)處理異步流程,以(yǐ) key/value 格式定義,返回值必須是(shì) Promise

thunk: {
  thunk1: (action, {put, select}) => {
    return new Promise(fn)
  }
}

Thunk 的(de)觸發同樣是(shì)通過 dispatch

dispatch({
  type: 'namespace/thunk1',
  payload: {},
  async: true
})

注意:這(zhè)裏的(de) async:true 爲(wéi / wèi)必傳字段,我們的(de)中間件 apolloMiddleware 将以(yǐ)此判斷該 Action 是(shì)否爲(wéi / wèi)一(yī / yì /yí)個(gè) Thunk ,并執行對應的(de)方法。

Subscription

Subscription 用于(yú)訂閱一(yī / yì /yí)個(gè)數據源,然後根據條件 dispatch 需要(yào / yāo)的(de) Action。數據源可以(yǐ)是(shì)當前的(de)時(shí)間、服務器的(de) Websocket 連接、Keyboard 輸入、Geolocation 變化、History 路由變化等等。

subscription: {
  setup: ({dispatch, history, listen}, onError) => {
    //使用 history 監控路由變化
    return history.listen((loaction)=> {console.log(loaction)})

    //使用 listen 監控路由變化

    //第二個(gè)參數可以(yǐ)是(shì)個(gè) Action, 匹配 /test 路由時(shí) dispatch 這(zhè)個(gè) Action
    return listen('/test', {type:'test'}) 
    //第二個(gè)參數可以(yǐ)是(shì)個(gè) function, 匹配 /test 路由時(shí)調用該回調
    return listen('/test/:id', ({params, query})=> {}) 
    //第一(yī / yì /yí)個(gè)參數可以(yǐ)是(shì) object ,對多個(gè) path 進行監聽
    return listen({
      '/test':({params, query})=> {},
      '/test1':({params, query})=> {},
    }) 

    return listen({
      '/test':{type:'test'},
      '/test1':{type:'test1'}
    }) 
  }
}

Router

這(zhè)裏的(de)路由通常指的(de)是(shì)前端路由,由于(yú)我們的(de)應用現在(zài)通常是(shì)單頁應用,所以(yǐ)需要(yào / yāo)前端代碼來(lái)控制路由邏輯,通過浏覽器提供的(de) History API 可以(yǐ)監聽浏覽器 url 的(de)變化,從而(ér)控制路由相關操作。

apollo 所提供的(de)路由方法主要(yào / yāo)依賴于(yú)目前最爲(wéi / wèi)流行的(de) react-router 工具庫,它是(shì)一(yī / yì /yí)個(gè)基于(yú) react 之(zhī)上(shàng)的(de)強大(dà)路由庫,它可以(yǐ)讓你向應用中快速地(dì / de)添加視图和(hé / huò)數據流,同時(shí)保持頁面與 URL 間的(de)同步。我們通過對 react-router 和(hé / huò) redux 的(de)結合,實現了(le/liǎo)數據流的(de)全方位整合,爲(wéi / wèi) Store 的(de)持久化等操作提供了(le/liǎo)實現基礎。

快速上(shàng)手

依照慣例,我們來(lái)基于(yú) apollo 實現一(yī / yì /yí)個(gè) todo-list 應用。其核心思想就(jiù)是(shì)我們有一(yī / yì /yí)個(gè) list,用來(lái)存儲每一(yī / yì /yí)條待辦事項,并且允許用戶添加或者移除待辦事項。所以(yǐ),我們先來(lái)進行第一(yī / yì /yí)步:

第1步:構建 Model

Model 是(shì) apollo 框架的(de)核心部分,包含數據存儲以(yǐ)及業務代碼其組成如下:

  • namespace: 表示這(zhè)個(gè) Model 屬于(yú)哪個(gè)模塊,語義上(shàng)應該負責什麽功能,與其他(tā) Model 區分開來(lái)。
  • state: 表示這(zhè)個(gè)功能模塊會存儲哪些數據。
  • reducer: 負責更改 State 的(de)方法。
  • thunk:處理異步請求的(de)方法(返回 Promise )。

創建models/todo.js,内容如下:

import * as todoService from '../services/todo'; 
export default {
  namespace: 'todo', 
  state: {
    list: [], 
  },
  reducer: {
    save(state, {payload: item}) {
      const list = [...state.list, item]

      return {...state, list} 
    },
    remove(state, {payload: index}){ 
      state.list.splice(index, 1); 
      const list = [...state.list]; 

      return {...state, list}
    } 
  },
  thunk: {
    addTodo({payload: todo}, {put, select}){
      return todoService.addTodo(todo).then( res => { 
        put({
          type: 'todo/save',
          payload: res
        });
      }) 
    },
    removeTodo({payload: index}, {put, select}){
      return todoService.removeTodo(index).then( res => {
        put({
          type: 'todo/remove', 
          payload: res
        }) 
      })
    }
  }
};

redux 的(de)核心思想之(zhī)一(yī / yì /yí)就(jiù)是(shì)統一(yī / yì /yí)的(de) state,我們将我們應用的(de) model 構建出(chū)來(lái),針對 todo-list 這(zhè)個(gè)部分,告訴框架 state 裏需要(yào / yāo)放什麽,有哪些影響 state 的(de) reducer,有哪些負責發起 reducer 的(de) thunk

這(zhè)裏的(de) namespace 很重要(yào / yāo),是(shì) apollo 将幾個(gè)部件相互連接起來(lái)的(de)依據。我們 state 中描述這(zhè)個(gè)模塊我們需要(yào / yāo)一(yī / yì /yí)個(gè)名爲(wéi / wèi) list 的(de)數組,然後有兩個(gè) reducer 分别是(shì)往 list 中增加一(yī / yì /yí)條 todo 和(hé / huò)删除一(yī / yì /yí)條 todo,再到(dào)後面有兩個(gè) thunk,分别從服務層去調用相應的(de) API (此處模拟),并最終發起 reduce 來(lái)更新 state

注意 thunk 的(de)第二參數中的(de)第二個(gè)值 select ,可以(yǐ)用來(lái)在(zài) thunk 中獲取 state 裏面的(de)變量:

const name = select(({name}) => name)

第2步:構建 services

這(zhè)一(yī / yì /yí)步是(shì)可選的(de),隻是(shì)爲(wéi / wèi)了(le/liǎo)将業務服務與 model 分離開來(lái),使得代碼結構更清晰,所以(yǐ)引入 service 的(de)概念。

上(shàng)一(yī / yì /yí)步中,我們看到(dào) models 裏邊引入了(le/liǎo) todoService,這(zhè)裏就(jiù)要(yào / yāo)來(lái)創建這(zhè)個(gè) service

//可以(yǐ)在(zài)此引用其他(tā)的(de) HTTP request 庫,或者任何處理 AJAX 請求的(de)庫。
export const addTodo = todo => { 
  //常規應用中這(zhè)裏應當放置異步請求(GET,POST等)方法,這(zhè)些方法同樣也(yě)是(shì)返回一(yī / yì /yí)個(gè) Promise 
  return new Promise((resolve, reject) => {
    setTimeout(()=>{ 
      resolve(todo)
    }, 2000) 
  })
}

export const removeTodo = index => {
  return new Promise((resolve, reject) => { 
    //常規應用中這(zhè)裏應當放置異步請求(GET,POST等)方法,這(zhè)些方法同樣也(yě)是(shì)返回一(yī / yì /yí)個(gè) Promise
    setTimeout(()=>{ 
      resolve(index)
    }, 2000) 
  })
}

此處隻是(shì)定時(shí)兩秒之(zhī)後返回傳進來(lái)的(de)參數,做了(le/liǎo)一(yī / yì /yí)個(gè)假的(de)異步請求。

當然,如果是(shì)在(zài)做一(yī / yì /yí)個(gè)實際的(de) web 應用,這(zhè)裏放的(de)就(jiù)是(shì) AJAX 請求方法,并把方法本身(也(yě)返回一(yī / yì /yí)個(gè) Promise ) return 回去,讓 thunk 去調用 .then 方法。目前已有很多基于(yú) AJAX 的(de) Promise 實現,例如 axios

這(zhè)一(yī / yì /yí)步驟可以(yǐ)省略,你也(yě)可以(yǐ)直接在(zài) model 中引入并在(zài) Thunk 中調用自己的(de) AJAX 請求方法。隻是(shì)分離出(chū)來(lái)的(de)話代碼結構更清晰一(yī / yì /yí)些。

第3步:構建實際的(de) component

創建 src/components/todo-list/index.js,代碼如下:

import React from 'react';
import { connect } from 'apollo';
import './index.css';

const TodoList = (props) => {
  const showPrompt = () => {
    props.addTodo(window.prompt('What do you want to do?'));
  }

  return (
    <div>
      <ul className="todos">
        {
          props.list.length > 0 ? props.list.map((item, index) => (
            <li>
              {item}
              <button onClick={() => { props.removeTodo(index) }}>
                删除
              </button>
            </li>
          )) : null
        }
      </ul>
      <button onClick={showPrompt}>新增</button>
    </div>
  )
}

const mapDispatchToProps = (dispatch) => {
  return {
    addTodo(todo) {
      dispatch({
        type: 'todo/addTodo',
        payload: todo,
        async: true
      })
    },
    removeTodo(index) {
      dispatch({
        type: 'todo/removeTodo',
        payload: index,
        async: true
      })
    }
  }
}

const mapStateToProps = ({ todo }) => {
  return {
    ...todo
  };
}
export default connect(mapStateToProps, mapDispatchToProps)(TodoList)

注意此處我們使用的(de)是(shì)一(yī / yì /yí)個(gè)純函數組件,其有一(yī / yì /yí)個(gè)參數即 props

我們先看最後定義的(de)兩個(gè)方法,一(yī / yì /yí)個(gè)是(shì) mapDispatchToProps,接收一(yī / yì /yí)個(gè)參數 dispatch,此處 dispatch 會由框架傳遞,是(shì)用于(yú)發起 Action(thunk) 的(de)方法。所以(yǐ)這(zhè)裏就(jiù)封裝了(le/liǎo)最後由 component 的(de)一(yī / yì /yí)些事件觸發的(de) Thunk 或者 Reducer 調用,這(zhè)裏具體就(jiù)是(shì)增加 Todo 和(hé / huò)删除 Todo,注意此處 dispatch 接收的(de)參數中 async 爲(wéi / wèi) true,代表我們要(yào / yāo)調用的(de)這(zhè)個(gè)東⻄是(shì) Thunk,如果不(bù)用 async 的(de)話則代表我們希望直接調用 reducer

另一(yī / yì /yí)個(gè)方法則是(shì) mapStateToProps,顧名思義就(jiù)是(shì)将 apollo 管理的(de)整個(gè) state 中相關的(de)部分映射到(dào)這(zhè)個(gè)組件的(de) props 中來(lái)。注意此處接收的(de)參數是(shì)整個(gè) app 的(de) state,我們寫成 {todo} 意味着我們隻接受 state.todo,然後我們将 state.todo 中的(de)東⻄給返回去。

最重要(yào / yāo)的(de)一(yī / yì /yí)部分,也(yě)就(jiù)是(shì)開頭引入的(de) connect 方法。 export 這(zhè)個(gè)組件的(de)時(shí)候我們将 mapStateToProps 和(hé / huò) action 都與 TodoList 進行連接,會将它們都注入組件的(de) props。此時(shí)這(zhè)個(gè)組件 render 時(shí)我們就(jiù)可以(yǐ)使用 props.list (從 model 中映射過來(lái)的(de)),并且以(yǐ)兩個(gè) button 來(lái)發起 props.addTodo 和(hé / huò) props.removeTodo 了(le/liǎo)。

第4步:創建 router(或新的(de) component 加入 router)

import React from 'react';
import { Router, Route } from 'apollo/router';

const cached = {};

const registerModel = (app, model) => {
  if (!cached[model.namespace]) { 
    app.model(model); 
    cached[model.namespace] = 1;
  } 
}

const RouterConfig = ({history, app}) => { 
  return (
    <Router history={history}>
      <Route path="/" getComponent={(nextState, cb) => {
        require.ensure([], (require) => {
          registerModel(app, require('../models/todo').default); 
          cb(null, require('../components/todo-list/index').default);
        }); 
      }} />
    </Router> 
  )
}

export default RouterConfig;

apollo 也(yě)提供了(le/liǎo) Router 的(de)引用,所以(yǐ)直接可以(yǐ)從 apollo/router 中引入 react-router 或者 react-router-redux

需要(yào / yāo)注意的(de)一(yī / yì /yí)點是(shì)這(zhè)裏有一(yī / yì /yí)個(gè) registerModel,封裝了(le/liǎo)調用 app.model 去注冊 model 的(de)方法。這(zhè)裏的(de) model 就(jiù)是(shì)之(zhī)前我們定義的(de)那個(gè) model

然後由于(yú)我們做的(de)内容比較簡單,隻是(shì)一(yī / yì /yí)個(gè) todo-list,所以(yǐ)我們這(zhè)裏就(jiù)隻使用 / 作唯一(yī / yì /yí)的(de)路由了(le/liǎo)。在(zài)指定 component 時(shí)我們需要(yào / yāo)調用 registerModel 來(lái)注冊對應的(de) model,這(zhè)樣我們才能正确的(de) connect 對應的(de)内容到(dào)組件上(shàng)。

第5步:啓動應用

import React from 'react';
import createApollo from 'apollo'; 
import Router from './router/router'; 
import './index.css';

// 1. Initialize
const app = createApollo(); 

// 2. Plugins
// app.use(createLoading()); 

// 3. Router
app.router(Router);

// 4. Start
app.start('#root');

隻需4步,我們就(jiù)可以(yǐ)啓動剛才創建的(de) todo-list 了(le/liǎo)。注意我們這(zhè)裏省去了(le/liǎo)第2步,也(yě)就(jiù)是(shì)插件,這(zhè)裏沒有用到(dào)。 另一(yī / yì /yí)個(gè)注意的(de)地(dì / de)方就(jiù)是(shì) app.start 的(de)參數,就(jiù)是(shì)模闆 HTML 中的(de) div 的(de)名字。

第6步:npm start

啓動 dev 服務器:

$ npm start

浏覽器會自動打開 localhost:3000 ,測試一(yī / yì /yí)下我們構建的(de) todo-list 吧!

API

app = apollo(opts)

創建應用,返回 apollo 實例。 opts 包含

  • history:指定給路由用的(de) history,默認是(shì) hashHistory
  • onThunkType: 指定 onThunk 的(de)增強方式,默認是(shì) all。普通開發人(rén)員無需關注該接口

如果要(yào / yāo)配置 history 爲(wéi / wèi) browserHistory,可以(yǐ)這(zhè)樣:

import { browserHistory } from 'apollo/router';
const app = apollo({
  history: browserHistory,
});

另外,出(chū)于(yú)易用性的(de)考慮,opts 裏也(yě)可以(yǐ)配所有的(de) hooks ,下面包含全部的(de)可配屬性:

const app = apollo({
  history,
  initialState,
  onError,
  onAction,
  onStateChange,
  onReducer,
  onThunk,
  extraReducers,
  extraEnhancers,
  onThunkType
});

app.use(hooks)

配置 hooks 或者注冊插件。(插件最終返回的(de)是(shì) hooks ) hooks 包含: onError(fn, dispatch) thunk 執行錯誤時(shí)觸發,可用于(yú)管理全局出(chū)錯狀态。如果 thunk 主動對 error 進行 catch,不(bù)會觸發該鈎子(zǐ)。

const app = apollo({
  onError(e, dispatch) {
    alert(e.message);
    dispatch({
      type: 'errorHandle',
      payload: e
    })
  },
});

onAction(fn | fn[])

在(zài) action 被 dispatch 時(shí)觸發,用于(yú)注冊 redux 中間件。支持函數或函數數組格式。

例如我們要(yào / yāo)通過 redux-logger 打印日志;

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

onStateChange(fn)

state 改變時(shí)觸發,可用于(yú)同步 state 到(dào) localStorage,服務器端等。其中 fn 的(de)入參爲(wéi / wèi)當前 state。

const app = apollo({
  onStateChange: function (state) {
    console.log('onStateChange:');
    console.log(state);
  }
});

onReducer(fn) 封裝 reducer 執行。

onReducer: function (reducer) {
  return function(state, action) {
    console.log('onReducer!!!')
    return reducer(state,action);
  }
}

onThunk(fn) 封裝 thunk 執行。onThunk 必須返回一(yī / yì /yí)個(gè) promise

const app = apollo({
  onThunk(thunk, {put, select}) {
    return new Promise(function (resolve, reject) {
      put({
        type: '@@APOLLO_LOADING/SHOW'
      });
      resolve('success');
    }).then(function () {
      return thunk.call(thunk)
    }).then(function (val) {
      put({
        type: '@@APOLLO_LOADING/HIDE'
      });
      return val
    })
  },
})

extraReducers 指定額外的(de) reducer。

const app = apollo({
  extraReducers: {
    extra: extraReducer
  }
})

extraEnhancers 指定額外的(de) StoreEnhancer。StoreEnhancer請參考 redux 的(de) StoreEnhancer。

以(yǐ)上(shàng)所有關于(yú) hooks 初始化設置都可以(yǐ)使用 app.use(hooks) 來(lái)完成。

const app = apollo();
app.use({
  onError,
  onAction,
  onStateChange,
  onReducer,
  onThunk,
  extraReducers,
  extraEnhancers,
})

app.model(model)

注冊 model。 model model 是(shì) apollo 中最重要(yào / yāo)的(de)概念,以(yǐ)下是(shì)典型的(de)例子(zǐ):

app.model({
  namespace: 'user',
  state: {
    name: ''
  },
  reducer: {
    setName: function(prevState, {payload: name}) {
      return {...prevState, name}
    }
  },
  thunk: {
    getName: function({payload}, {put}) {
      return fetch('/api/getUserName')
        .then(function(res){
          put({
            type: 'user/setName',
            payload: res.name
          })
        })
    }
  }
})

model 包含 5 個(gè)屬性:

  • namespace

model 的(de)命名空間,同時(shí)也(yě)是(shì)他(tā)在(zài)全局 state 上(shàng)的(de)屬性,隻能用字符串,不(bù)支持通過 . 的(de)方式創建多層命名空間。

  • state

初始狀态值

  • reducer

以(yǐ) key/value 格式定義 reducer。用于(yú)處理同步操作,唯一(yī / yì /yí)可以(yǐ)修改 state 的(de)地(dì / de)方。由 action 觸發。每個(gè) reducer 對應的(de) actionType 爲(wéi / wèi) @namespace/@recuder-key

格式爲(wéi / wèi) (state, action) => newState

  • thunk

以(yǐ) key/value 格式定義 thunk。用于(yú)異步操作。thunk的(de)入參如下:

thunk: {
  thunk1: function(action, {put, select}) {
    return new Promise(fn)
  }
}

thunk 第一(yī / yì /yí)個(gè)參數是(shì) action, 第二個(gè)參數是(shì)個(gè) object,裏面包含了(le/liǎo) put 和(hé / huò) select 方法。其中 put 等同于(yú) dispatchselect 用于(yú)選擇當前 state 值,隻能選擇該 model 中的(de) state

const name = select(({name}) => name)

thunk 必須返回一(yī / yì /yí)個(gè) promise。

  • subscription

以(yǐ) key/value 格式定義 subscription。subscription 是(shì)訂閱,用于(yú)訂閱一(yī / yì /yí)個(gè)數據源,然後根據需要(yào / yāo) dispatch 相應的(de) action。在(zài) app.start() 或者異步加載 model 時(shí)執行

subscription: {
  setup: function({dispatch, history, listen}, onError) {
    //使用 history 監控路由變化
    return history.listen((loaction)=> {console.log(loaction)})

    //使用 listen 監控路由變化

    //第二個(gè)參數可以(yǐ)是(shì)個(gè) action, 匹配 /test 路由時(shí) dispatch 這(zhè)個(gè) action
    return listen('/test', {type:'test'}) 
    //第二個(gè)參數可以(yǐ)是(shì)個(gè) function, 匹配 /test 路由時(shí)調用該回調
    return listen('/test/:id', ({params, query})=> {}) 
    //第一(yī / yì /yí)個(gè)參數可以(yǐ)是(shì) object,對多個(gè) path 進行監聽
    return listen({
      '/test':({params, query})=> {},
      '/test1':({params, query})=> {},
    }) 

    return listen({
      '/test':{type:'test'},
      '/test1':{type:'test1'}
    }) 
  }
}

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

注冊路由表。

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

也(yě)可以(yǐ)傳入返回 JSX 元素的(de)函數。比如:

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

app.start(selector?)

啓動應用。selector 可選,如果沒有 selector 參數,會返回一(yī / yì /yí)個(gè)返回 JSX 元素的(de)函數。

app.start('#root');

const App = app.start();
ReactDom.render(<App/>, el)
Copyright © 屯昌單支科技有限公司 2019 all right reserved,powered by Gitbook聯系方式: wanglihang@mskj.com
修訂時(shí)間: 2019-08-02 16:19:32

results matching ""

    No results matching ""