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