apollo
apollo
是(shì)一(yī / yì /yí)個(gè)基于(yú) redux
和(hé / huò) redux-thunk
的(de)數據流解決方案,通過對 react
、 redux
、 react-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)可維護性。
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) Store
。Action
必須帶有 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ú) dispatch
。 select
用于(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)