摘要:新的項目目錄設(shè)計如下放置靜態(tài)文件業(yè)務(wù)組件入口文件數(shù)據(jù)模型定義數(shù)據(jù)定義工具函數(shù)其中數(shù)據(jù)流實踐的核心概念就是數(shù)據(jù)模型和數(shù)據(jù)儲存。最后再吃我一發(fā)安利是阿里云業(yè)務(wù)運營事業(yè)部前端團隊開源的前端構(gòu)建和工程化工具。
本文首發(fā)于阿里云前端dawn團隊專欄。
項目在最初應(yīng)用 MobX 時,對較為復(fù)雜的多人協(xié)作項目的數(shù)據(jù)流管理方案沒有一個優(yōu)雅的解決方案,通過對MobX官方文檔中針對大型可維護項目最佳實踐的學(xué)習(xí)和應(yīng)用,把自己的理解抽象出一個簡單的todoMVC應(yīng)用,供大家交流和討論。
搭建開發(fā)環(huán)境 安裝Dawn要求 Node.js v7.6.0 及以上版本。
$ [sudo] npm install dawn -g初始化工程
$ dawn init -t front
這里我選擇使用無依賴的 front 模板,便于自定義我的前端工程。
目錄結(jié)構(gòu)分析由 dawn 工具生成的項目目錄如下:
. ├── .dawn # dawn 配置文件 ├── node_modules ├── src │?? ├── assets │?? └── index.js ├── test # 單元測試 ├── .eslintrc.json ├── .eslintrc.yml ├── .gitignore ├── .npmignore ├── README.md ├── package.json ├── server.yml └── tsconfig.json
其中我們重點需要關(guān)注的是 src 目錄,其中的 index.js 就是我們項目的入口文件。
安裝依賴"devDependencies": { "react": "^15.6.1", "react-dom": "^15.6.1" }, "dependencies": { "mobx": "^3.2.2", "mobx-react": "^4.2.2", // 以下是todoMVC樣式模塊 "todomvc-app-css": "^2.1.0", "todomvc-common": "^1.0.4" }
安裝好依賴,環(huán)境就配置完成了,整個環(huán)境搭建過程只需要3步,開箱即用,不需要關(guān)注 Webpack 和 ESLint 等開發(fā)環(huán)境的繁瑣配置。當(dāng)然,Dawn 也完全支持自定義這些工具的配置。
todoMVC with MobX新的項目目錄設(shè)計如下:
... ├── src │ ├── assets # 放置靜態(tài)文件 │ │ ├── common.less │ │ ├── favicon.ico │ │ └── index.html │ ├── components # 業(yè)務(wù)組件 │ │ ├── todoApp.js │ │ ├── todoEntry.js │ │ ├── todoItem.js │ │ └── todoList.js │ ├── index.js # 入口文件 │ ├── models # 數(shù)據(jù)模型定義 │ │ └── TodoModel.js │ ├── stores # 數(shù)據(jù)store定義 │ │ ├── TodoStore.js │ │ ├── ViewStore.js │ │ └── index.js │ └── utils # 工具函數(shù) │ └── index.js ...
其中 MobX 數(shù)據(jù)流實踐的核心概念就是數(shù)據(jù)模型(Model)和數(shù)據(jù)儲存(Store)。
定義數(shù)據(jù)模型數(shù)據(jù)模型即為 MVVM(Model/View/ViewModel) 中的 Model。早期的前端開發(fā),需求比較簡單,大多是基于后端傳輸?shù)臄?shù)據(jù)去直接填充頁面中的“坑位”,沒有定義數(shù)據(jù)模型的意識。但隨著前端業(yè)務(wù)復(fù)雜度和數(shù)據(jù)傳輸量的不斷上升,如果沒有數(shù)據(jù)模型的定義,在多人協(xié)作時會讓前端系統(tǒng)維護的復(fù)雜性和不可控性急劇上升,直觀體現(xiàn)就是其它人對數(shù)據(jù)做改動時,很難覆蓋到改動的某個字段會產(chǎn)生的全部影響,直接導(dǎo)致維護的周期和難度不斷增加。
定義數(shù)據(jù)模型有以下好處:
讓數(shù)據(jù)源變的可控,可以清晰的了解到定義字段的含義、類型等信息,是數(shù)據(jù)的天然文檔,對多人協(xié)作大有裨益。通過應(yīng)用面向?qū)ο蟮乃枷耄部梢栽谀P椭卸x一些屬性和方法供創(chuàng)建出的實例使用。
實現(xiàn)前端數(shù)據(jù)持久化,單頁應(yīng)用經(jīng)常會遇到多頁面數(shù)據(jù)共享和實時更新的問題,通過定義數(shù)據(jù)模型并創(chuàng)建實例,可以避免異步拉取來的數(shù)據(jù)進行 View 層渲染后就被銷毀。
下面是待辦事項的數(shù)據(jù)模型定義:
import { observable } from "mobx"; class TodoModel { store; id; @observable title; @observable completed; /** * 創(chuàng)建一個TodoModel實例 * 用于單個todo列表項的操作 * @param {object} store 傳入TodoStore,獲取領(lǐng)域模型狀態(tài)和方法 * @param {string} id 用于前端操作的實例id * @param {string} title todo項的內(nèi)容 * @param {boolean} completed 是否完成的狀態(tài) * @memberof TodoModel */ constructor(store, id, title, completed) { this.store = store; this.id = id; this.title = title; this.completed = completed; } // 切換列表項的完成狀態(tài) toggle = () => { this.completed = !this.completed; } // 根據(jù)id刪除列表項 delete = () => { this.store.todos = this.store.todos .filter(todo => todo.id !== this.id); } // 設(shè)置實例title setTitle = (title) => { this.title = title; } } export default TodoModel;
從 TodoModel 的定義中可以清楚的看到一個待辦事項擁有的屬性和方法,通過這些,就可以對創(chuàng)建出的實例進行相應(yīng)的操作。但是在實例中只能修改實例自身的屬性,怎樣才能把待辦事項的狀態(tài)變化通過 viewModel 來渲染到 view 層呢?
定義數(shù)據(jù)儲存官方文檔對數(shù)據(jù)儲存的定義是這樣的:
Stores can be found in any Flux architecture and can be compared a bit with controllers in the MVC pattern. The main responsibility of stores is to move logic and state out of your components into a standalone testable unit.
翻譯過來是:數(shù)據(jù)儲存(Store)可以在任何 Flux 系架構(gòu)中找到,可以與 MVC 模式中的控制器(Controller)進行類比。它的主要職責(zé)是將邏輯和狀態(tài)從組件中移至一個獨立的,可測試的單元。
也就是說,Store 就是連接我們的 View 層和 Model 層之間的橋梁,即 ViewModel,所有的狀態(tài)和邏輯變化都應(yīng)該在 Store 中完成。同一個 Store 不應(yīng)該在內(nèi)存中有多個實例,要確保每個 Store 只有一個實例,并允許我們安全地對其進行引用。
下面通過項目示例來更清晰的理解這個過程。
首先是 todoMVC 的數(shù)據(jù) Store 定義:
import { observable } from "mobx"; import { uuid } from "../utils"; import TodoModel from "../models/TodoModel"; class TodoStore { // 保存todo列表項 @observable todos = []; // 添加todo,參數(shù)為todo內(nèi)容 // 注意:此處傳入的 this 即為 todoStore 實例的引用 // 通過引用使得 TodoModel 有了調(diào)用 todoStore 的能力 addTodo(title) { this.todos.push( new TodoModel(this, uuid(), title, false) ); } } export default TodoStore;
需要注意的是,在創(chuàng)建 TodoModel 傳入的 this 即為 todoStore 實例的引用,通過這里的引用使得 TodoModel 的實例擁有了調(diào)用 todoStore 的能力,這也就是我們要保證數(shù)據(jù)儲存的 Store 只有一個實例的原因。
然后是視圖層對數(shù)據(jù)進行渲染的方式:
import React, { Component } from "react"; import { computed } from "mobx"; import { inject, observer } from "mobx-react"; import TodoItem from "./todoItem"; @inject("todoStore") @observer class TodoList extends Component { @computed get todoStore() { return this.props.todoStore; } render() { const { todos } = this.todoStore; return (); } } export default TodoList; {todos.map(todo =>
)}
我們把這個過程分步來理解:
首先,拿到待辦事項的內(nèi)容(title)和完成狀態(tài),通過 TodoModel 創(chuàng)建一個新的待辦事項的實例。
其次,在 todoStore 中把每個創(chuàng)建出的 TodoModel 實例填入 todos 數(shù)組,用于待辦事項列表的渲染。
最后,在視圖層中通過 inject 裝飾器注入todoStore,從而引用其中的 todos 數(shù)組,MobX 會響應(yīng)數(shù)組的變化完成渲染。
如果待辦事項的內(nèi)容和完成狀態(tài)需要改動,就要修改 Model 中對應(yīng)的類型屬性,然后在 todoStore 中進行相應(yīng)的加工,最后產(chǎn)出新的視圖展示。而在這個過程中,我們只需要把可能會變化的屬性定義為可觀察的變量,在需要變更的時候進行修改,剩余的工作 MobX 會幫我們完成。
定義用戶界面狀態(tài)剛才定義的 todoStore 是針對數(shù)據(jù)儲存的,但是對于前端來講,還有很大一部分工作是 UI 的狀態(tài)管理。
UI 的狀態(tài)通常沒有太多的邏輯,但會包含大量松散耦合的狀態(tài)信息,同樣可以通過定義 UI Store 來管理這部分狀態(tài)。
以下是一個 UI Store 的簡單定義:
import { observable } from "mobx"; export default class ViewStore { @observable todoBeingEdited = null; }
這個 Store 只包含一個可觀察的屬性,用于保存正在編輯的 TodoModal 實例,通過這個屬性來控制視圖層待辦事項的修改:
... class TodoItem extends Component { ... edit = () => { // 設(shè)置 todoBeingEdited 為當(dāng)前待辦事項todo的實例 this.viewStore.todoBeingEdited = this.todo; this.editText = this.todo.title; }; ... handleSubmit = () => { const val = this.editText.trim(); if (val) { this.todo.setTitle(val); this.editText = val; } else { this.todo.delete(); } // 提交修改后初始化 todoBeingEdited 變量 this.viewStore.todoBeingEdited = null; } render() { // 根據(jù) todoBeingEdited 和當(dāng)前 todo 比較的結(jié)果判斷是否處于編輯狀態(tài) const isEdit = expr(() => this.viewStore.todoBeingEdited === this.todo); const cls = [ this.todo.completed ? "completed" : "", isEdit ? "editing" : "" ].join(" "); return (
在視圖中對 UI Store 的可觀察的屬性進行修改,MobX 會收集相應(yīng)的變化經(jīng)過處理后響應(yīng)在視圖上。
源碼完整的 todoMVC 代碼可以通過以下方式獲取:
$ dawn init -t react-mobx
或者在 Github 上查看源碼:https://github.com/xdlrt/dn-t...
總結(jié)基于 MobX 的數(shù)據(jù)流管理方案,分為以下幾步:
定義數(shù)據(jù) Model,使數(shù)據(jù)源可控并可持久化
定義數(shù)據(jù) Store 和 UI Store,創(chuàng)建并管理數(shù)據(jù) Model 實例及實例屬性的變更
將 Store 注入到視圖層,使用其中的數(shù)據(jù)進行視圖渲染,MobX 自動響應(yīng)數(shù)據(jù)的變化更新視圖
以上是我對 MVVM 框架中使用 MobX 管理數(shù)據(jù)流的一些理解,同時這種方案也在團隊內(nèi)一個較為復(fù)雜的項目中進行實踐,目前項目的健壯性和可維護性比較健康,歡迎提出不同的見解,共同交流。
最后再吃我一發(fā)安利Dawn 是「阿里云-業(yè)務(wù)運營事業(yè)部」前端團隊開源的前端構(gòu)建和工程化工具。
它通過封裝中間件(middleware) ,如 webpack 和本地 server ,并在項目 pipeline 中按需使用,可以將開發(fā)過程抽象為相對固定的階段和有限的操作,簡化并統(tǒng)一開發(fā)環(huán)境,能夠極大地提高團隊的開發(fā)效率。
項目的模板即工程 boilerplate 也可以根據(jù)團隊的需要進行定制復(fù)用,實現(xiàn)「configure once run everywhere」。
歡迎體驗并提出意見和建議,幫助我們改進。Github地址:https://github.com/alibaba/dawn
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/89390.html
摘要:本文主要闡述了如何使用快速搭建一個多頁面應(yīng)用。而我司當(dāng)前的情況比較適合于使用多頁面應(yīng)用,既提高了開發(fā)效率,保證了用戶體驗,又極大的兼容了原有的體系。當(dāng)然也可以不復(fù)制不修改,此時就是一個單頁面應(yīng)用。 what 本文主要闡述了如何使用dawn快速搭建一個多頁面應(yīng)用。 why 單頁有許多優(yōu)缺點。而我司當(dāng)前的情況比較適合于使用多頁面應(yīng)用,既提高了開發(fā)效率,保證了用戶體驗,又極大的兼容了原有的P...
摘要:發(fā)布按照官方發(fā)布計劃,的發(fā)布意味著進入階段,徹底退出舞臺,的還有半年結(jié)束。為了應(yīng)對這個挑戰(zhàn),美團點評境外度假前端研發(fā)團隊自年月起啟動了面向端用戶的赫爾墨斯項目。前端技術(shù)越來越復(fù)雜,有不低的技術(shù)門檻。 推薦 1. 利用 Dawn 工程化工具實踐 MobX 數(shù)據(jù)流管理方案 https://zhuanlan.zhihu.com/p/... 項目在最初應(yīng)用 MobX 時,對較為復(fù)雜的多人協(xié)作項...
摘要:版本發(fā)布近日發(fā)布的版本中引入了許多新的特性,并且能夠更好地與協(xié)同開發(fā)。阿里云前端工程化工具正式開源取黎明破曉之意,原為阿里云業(yè)務(wù)運營團隊內(nèi)部的前端構(gòu)建和工程化工具,現(xiàn)已完全開源。 推薦 1. Firefox 引入 Headless 模式 https://developer.mozilla.org... 類似于 Chrome 的 Headless 模式,現(xiàn)在 Firefox 也引入了 H...
摘要:取黎明破曉之意,原為阿里云業(yè)務(wù)運營團隊內(nèi)部的前端構(gòu)建和工程化工具,現(xiàn)已完全開源。它通過和將開發(fā)過程抽象為相對固定的階段和有限的操作,簡化并統(tǒng)一了開發(fā)人員的日常構(gòu)建與開發(fā)相關(guān)的工作。 showImg(https://segmentfault.com/img/remote/1460000011006491); Dawn Dawn 取「黎明、破曉」之意,原為「阿里云·業(yè)務(wù)運營團隊」內(nèi)部的前端...
摘要:前端每周清單半年盤點之與篇前端每周清單專注前端領(lǐng)域內(nèi)容,以對外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點分為新聞熱點開發(fā)教程工程實踐深度閱讀開源項目巔峰人生等欄目。與求同存異近日,宣布將的構(gòu)建工具由遷移到,引發(fā)了很多開發(fā)者的討論。 前端每周清單半年盤點之 React 與 ReactNative 篇 前端每周清單專注前端領(lǐng)域內(nèi)容,以對外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點;分為...
閱讀 1230·2021-11-11 16:54
閱讀 1744·2021-10-13 09:40
閱讀 940·2021-10-08 10:05
閱讀 3503·2021-09-22 15:50
閱讀 3706·2021-09-22 15:41
閱讀 1800·2021-09-22 15:08
閱讀 2345·2021-09-07 10:24
閱讀 3578·2019-08-30 12:52