感謝阿里前端工程師@李凌豪投稿,文章首發在 qianduan.guru
Mirror 是一款基於 React、Redux 和 react-router 的前端框架,簡潔高效、靈活可靠。
為什麼?
我們熱愛 React 和 Redux。但是,Redux 中有太多的樣板檔案,需要很多的重複勞動,這一點令人沮喪;更別提在實際的 React 應用中,還要整合 react-router
的路由了。
一個典型的 React/Redux 應用看起來像下面這樣:
actions.js
export const ADD_TODO = 'todos/add'
export const COMPLETE_TODO = 'todos/complete'
export function addTodo(text) {
return {
type: ADD_TODO,
text
}
}
export function completeTodo(id) {
return {
type: COMPLETE_TODO,
id
}
}複製程式碼
reducers.js
import { ADD_TODO, COMPLETE_TODO } from './actions'
let nextId = 0
export default function todos(state = [], action) {
switch (action.type) {
case ADD_TODO:
return [...state, {text: action.text, id: nextId++}]
case COMPLETE_TODO:
return state.map(todo => {
if (todo.id === action.id) todo.completed = true
return todo
})
default:
return state
}
}複製程式碼
Todos.js
import { addTodo, completeTodo } from './actions'
// ...
// 在某個事件處理函式中
dispatch(addTodo('a new todo'))
// 在另一個事件處理函式中
dispatch(completeTodo(42))複製程式碼
看起來是不是有點繁冗?這還是沒考慮 非同步 action
的情況呢。如果要處理非同步 action
,還需要引入 middleware(比如 redux-thunk
或者 redux-saga
),那麼程式碼就更繁瑣了。
使用 Mirror 重寫
Todos.js
import mirror, { actions } from 'mirrorx'
let nextId = 0
mirror.model({
name: 'todos',
initialState: [],
reducers: {
add(state, text) {
return [...state, {text, id: nextId++}]
},
complete(state, id) {
return state.map(todo => {
if (todo.id === id) todo.completed = true
return todo
})
}
}
})
// ...
// 在某個事件處理函式中
actions.todos.add('a new todo')
// 在另一個事件處理函式中
actions.todos.complete(42)複製程式碼
是不是就簡單很多了?只需一個方法,即可定義所有的 action
和 reducer
(以及 非同步 action
)。
而且,這行程式碼:
actions.todos.add('a new todo')複製程式碼
完全等同於這行程式碼:
dispatch({
type: 'todos/add',
text: 'a new todo'
})複製程式碼
完全不用關心具體的 action type
,不用寫大量的重複程式碼。簡潔,高效。
非同步 action
上述程式碼示例僅僅針對同步 action
。
事實上,Mirror 對非同步 action
的處理,也同樣簡單:
mirror.model({
// 省略前述程式碼
effects: {
async addAsync(data, getState) {
const res = await Promise.resolve(data)
// 呼叫 `actions` 上的方法 dispatch 一個同步 action
actions.todos.add(res)
}
}
})複製程式碼
沒錯,這樣就定義了一個非同步 action。上述程式碼的效果等同於如下程式碼:
actions.todos.addSync = (data, getState) => {
return dispatch({
type: 'todos/addAsync',
data
})
}複製程式碼
呼叫 actions.todos.addSync
方法,則會 dispatch 一個 type 為 todos/addAsync
的 action。
你可能注意到了,處理這樣的 action,必須要藉助於 middleware。不過你完全不用擔心,使用 Mirror 無須引入額外的 middleware,你只管定義 action/reducer,然後簡單地呼叫一個函式就行了。
更簡單的路由
Mirror 完全按照 react-router 4.x 的介面和方式定義路由,因此沒有任何新的學習成本。
更方便的是,Mirror 的 Router
元件,其 history 物件以及跟 Redux store
的聯結是自動處理過的,所以你完全不用關心它們,只需關心你自己的各個路由即可。
而且,手動更新路由也非常簡單,呼叫 actions.routing
物件上的方法即可更新。
理念
Mirror 的設計理念是,在儘可能地避免發明新的概念,並保持現有開發模式的前提下,減少重複勞動,提高開發效率。
Mirror 總共只提供了 4 個新的 API,其餘僅有的幾個也都是已存在於 React/Redux/react-router 的介面,只不過做了封裝和強化。
所以,Mirror 並沒有“顛覆” React/Redux 開發流,只是簡化了介面呼叫,省去了樣板程式碼:
在對路由的處理上,也是如此。
如何使用?
使用 create-react-app 建立一個新的 app:
$ npm i -g create-react-app
$ create-react-app my-app複製程式碼
建立之後,從 npm 安裝 Mirror:
$ cd my-app
$ npm i --save mirrorx
$ npm start複製程式碼
檢視 文件 瞭解更多。
誰在使用?
Mirror 由阿里巴巴 FGT 前端團隊開發,目前在整個集團內部已有多個使用 React 技術棧的團隊使用。