Omi 6.0 - Store 的設計哲學

寫在前面

Store 是 Omi 內置的中心化數據倉庫,他解決了下面兩個問題:javascript

  • 組件樹數據共享
  • 數據變動按需更新依賴的組件

而這一切都是在運行時搞定。css

一段代碼徹底上手 Store

import { render, WeElement, define } from 'omi'

define('my-counter', class extends WeElement {
  static use = [
    { count: 'count' }
  ]

  add = () => this.store.add()
  sub = () => this.store.sub()

  addIfOdd = () => {
    if (this.use.count % 2 !== 0) {
      this.store.add()
    }
  }

  addAsync = () => {
    setTimeout(() => this.store.add(), 1000)
  }

  render() {
    return (
      <p> Clicked: {this.use.count} times {' '} <button onClick={this.add}>+</button> {' '} <button onClick={this.sub}>-</button> {' '} <button onClick={this.addIfOdd}> Add if odd </button> {' '} <button onClick={this.addAsync}> Add async </button> </p>
    )
  }
})

render(<my-counter />, 'body', { data: { count: 0 }, sub() { this.data.count-- }, add() { this.data.count++ }, }) 複製代碼

這是一個簡單的例子,說明了 store 體系的基本用法:html

  • 經過 static use 聲明依賴的 path
  • store 經過 render 的第三個參數從根節點注入到全部組件。
  • 調用組件的方法或者直接改變組件的 data 進行視圖更新

這裏在書寫過程當中會出現兩種方式,一種是將全部數據和邏輯放在 store 裏,一種是將部分共享數據放在 store 裏,這裏沒有強制要求使用哪一種方式,omi 這兩種能力都有,開發者偏心哪一種方式就使用哪一種方式。前端

複雜的例子

Store 裏的 data:java

{
  count: 0,
  arr: ['china', 'tencent'],
  motto: 'I love omi.',
  userInfo: {
    firstName: 'dnt',
    lastName: 'zhang',
    age: 18
  }
}
複製代碼

Static use:node

static use = [
  'count', //直接字符串,可經過 this.use[0] 訪問
  'arr[0]', //也支持 path,可經過 this.use[1] 訪問
  //支持 json
  {
    //alias,可經過 this.use.reverseMotto 訪問
    reverseMotto: [
      'motto', //path
      target => target.split('').reverse().join('')  //computed
    ]
  },
  { name: 'arr[1]' }, //{ alias: path },可經過 this.use.name 訪問
  {
    //alias,可經過 this.use.fullName 訪問
    fullName: [
      ['userInfo.firstName', 'userInfo.lastName'], //path array
      (firstName, lastName) => firstName + lastName //computed
    ]
  },
]
複製代碼

下面看看 JSX 中使用:git

...
...
render() {
  return (
    <div> <button onClick={this.sub}>-</button> <span>{this.use[0]}</span> <button onClick={this.add}>+</button> <div> <span>{this.use[1]}</span> <button onClick={this.rename}>rename</button> </div> <div>{this.use.reverseMotto}</div><button onClick={this.changeMotto}>change motto</button> <div>{this.use.name}</div> <div>{this.use[3]}</div> <div> {this.use.fullName} <button onClick={this.changeFirstName}>change first name</button> </div> </div>
  )
}
...
...
複製代碼

若是不帶有 alias ,你也能夠直接經過 this.store.data.xxx 訪問。github

Path 命中規則

store.data 發生變化,依賴變動數據的組件會進行更新,舉例說明 Path 命中規則:json

Proxy Path(由數據更改產生) static use 中的 path 是否更新
abc abc 更新
abc[1] abc 更新
abc.a abc 更新
abc abc.a 不更新
abc abc[1] 不更新
abc abc[1].c 不更新
abc.b abc.b 更新

以上只要命中一個條件就能夠進行更新!瀏覽器

總結: 只要注入組件的 path 等於 use 裏聲明 或者在 use 裏聲明的其中 path 子節點下就會進行更新!

解構賦值

import { define, WeElement } from 'omi'
import '../my-list'

define('my-sidebar', class extends WeElement {
  static css = require('./_index.css')

  static use = [
    'menus',
    'sideBarShow',
    'lan'
  ]

  render() {
    const [menus, sideBarShow, lan] = this.use

    return (
      <div class={`list${sideBarShow ? ' show' : ''}`}> {menus[lan].map((menu, index) => ( <my-list menu={menu} index={index} /> ))} </div> ) } }) 複製代碼

這裏舉了個例子使用 ES2015+ 語法 const [xx, xxx] = xxxx 的語法快速賦值。上面是從 omi docs 的源碼裏截取的部分。感興趣的能夠看看源碼。omi 官網已經使用 omi 6.0 重寫了。

設計哲學

回顧 Omi 從 1.0 到 6.0:

  • Omi 1.0 運行時動態模板引擎
  • Omi 2.0 擁抱虛擬 DOM 和運行時 scoped style
  • Omi 3.0 提供 native 模塊調用 bridge
  • Omi 4.0 擁抱 Web Components
  • Omi 5.0 糾正社區對 MVVM 誤解
  • Omi 6.0 擁抱多端統一,迎來全新 path updating 的 store 體系

1.0 使用的動態模板引擎,是圖靈完備的,能夠表達一切你想表達的結構。因爲是運行時,無法轉虛擬 DOM,必定要轉也能夠,開銷大,因此缺點很明顯,視圖更新開銷大,依賴真實 DOM 之間的的 diff,另一個缺點就是動態模板引擎(指令、模板語法均可以動態拼接)須要在腦海裏二次轉換,書寫起來不夠直觀、智能提示也沒有,不如 JSX 直接乾淨和智能。而爲何要這麼設計,從整個發展歷程來看離不開三個字: 運行時

Omi 的設計 1.0 敗也敗在運行時,成也成在運行時。從 2.0 開始,除了 JSX 的部分(固然能夠直接 hyperscript),其他所有 運行時 搞定:

  • 運行時的 scoped style
  • 運行時的 path updating 局部刷新

而到了 9210 年,JSX 也出現了運行時的替代方案:htm

爲什麼如此偏心運行時?而不交給編譯器去作?這個仁者見仁,智者見智,並且有個權衡在裏面。

當運行時的開銷對於用戶體驗能夠忽略不計,那麼就選擇運行時去作

運行時的好處很是明顯,不須要任何構建工具、編譯工具,就能夠在瀏覽器、node、javascript core 或者任何 javascript 環境直接運行。憑什麼讓我學那麼多構建工具、憑什麼和一堆工具耦合在一塊兒,我就是純粹的 js,想在哪裏跑均可以輕鬆複製粘貼或者直接 import/require 過去,而不強制帶上任何工具。固然這裏不是反對編譯工具對前端帶來的價值,omi-cli、omip、omi-mp 都大量使用了編譯工具,只是沒有編譯工具,omi 也能運行良好,簡單移植,好比 es module,好比 deno,直接 import 直接使用。

開始使用

相關文章
相關標籤/搜索