[譯] JSX 的替代方案

現在,JSX 已是一個很是受歡迎的框架模版了,它的應用也不只僅侷限於 React(或其餘 JSX 衍生模版)。可是,若是你並不喜歡它,或者有某些想要避免使用它的項目,或者只是好奇不使用 JSX 該如何書寫 React 代碼的時候,該怎麼辦呢?最簡單的方法就是去閱讀官方文檔,可是,官方文檔很簡短,而在本篇文章中咱們爲您提供了更多的選擇。html

免責聲明:我的來講,我很喜歡 JSX,在我全部的 React 項目中我都使用了它。可是,我對本文主題從新進行了調研,而且但願和你分享個人所見。前端

什麼是 JSX

首先,咱們須要明白什麼是 JSX,這樣咱們才能在純 JavaScript 中編寫對應的代碼。JSX 是一種特定域編程語言,意味着咱們須要將 JSX 代碼轉碼,以便獲得常規的 JavaScript,不然瀏覽器將沒法解析代碼。展望前景光明的將來,若是你想要使用 modules,而且全部須要的功能都能被目標瀏覽器支持,你仍然不能徹底丟棄轉碼這一步,這多是一個問題。node

也許理解 JSX 將會被解析成什麼最好的方法就是使用 babel repl 實際操做一次。你須要點擊左側面板的 presets 而且選擇 react,這樣解析器才能正確的解析代碼。這以後,你就能在右側實時看到編譯生成的 JavaScript 代碼。例如,你能夠嘗試下這段代碼:react

class A extends React.Component {
    render() {
        return (
            <div className={"class"} onclick={some}>
                {"something"}
                <div>something else</div>
            </div>
        )
    }
}
複製代碼

個人運行結果以下:android

class A extends React.Component {
  render() {
    return React.createElement("div", {
      className: "class",
      onclick: some
    }, "something", React.createElement("div", null, "something else"));
  }
}
複製代碼

能夠看到,每一個 <%tag%> 結構都被替換成了函數 React.createElement。第一個參數是 react 組件或者內建標籤名字符串(好比 divspan),第二個參數則是組件屬性,其餘的參數則都被視做組件的子元素。ios

我強烈推薦你使用不一樣結構的組件樹反覆嘗試,來觀察 React 如何渲染值爲 truefalse、數組、或者組件等的屬性:即便你只嘗試使用 JSX 和一些其餘內容的代碼,它也頗有幫助。git

若是你想深刻學習 JSX,能夠參考官方文檔github

重命名

因爲編譯結果是固定的,咱們其實也能夠將全部的 React 代碼直接以這種形式寫出,可是其實這種方式存在一些問題。web

第一個問題就是很是繁瑣。真的至關繁瑣,而罪魁禍首就是 React.createElement。因此這個問題的解決方案就是將它簡寫爲一個變量,按照 hyperscript 的方式命名爲 h。這種方式能節省不少代碼量,而且可讀性也更強。下面咱們來重寫上面的代碼,以便說明:編程

const h = React.createElement;
class A extends React.Component {
  render() {
    return h(
      "div",
      {
        className: "class",
        onclick: some
      },
      "something",
      h("div", null, "something else")
    );
  }
}
複製代碼

Hyperscript

若是 React.createElement 或者 h 你都已經嘗試過了,你就能夠看出它們都存在一些缺點。首先,函數須要三個參數,因此在沒有屬性的狀況下,你仍是必須傳遞 null 做爲參數,同時,className 做爲一個很經常使用的屬性,在每次使用的時候都須要新建一個對象。

做爲一個替代方案,你可使用 react-hyperscript 庫。它不須要你提供空屬性,而且容許你用點號的方式定義 class 和 id(div#main.content -> <div id="main" class="content">)。這樣,你的代碼能優化爲:

class A extends React.Component {
  render() {
    return h("div.class", { onclick: some }, [
      "something",
      h("div", "something else")
    ]);
  }
}
複製代碼

HTM

若是你並不反感 JSX 自己,可是不喜歡必需的代碼編譯,那麼你能夠試試看 htm 這個項目。它的目標就是完成和 JSX 相同的事情(而且代碼看上去也相同),可是使用的是模版字符串。它可能會帶來一些開銷(由於須要在運行時將模版解析),可是在某些狀況下也許也是值得的。

它的工做方式是將元素函數包裹起來,也就至關於前面例子中的 React.createElement,可是它支持任何其餘具備相似 API 的庫,同時僅在運行時編譯模版並返回和 babel 編譯結果同樣的代碼。

const html = htm.bind(React.createElement);
class A extends React.Component {
    render() {
        return html`
            <div className=${"class"} onclick=${some}>
                ${"something"}
                <div>something else</div>
            </div>
        `
    }
}
複製代碼

如你所見,結果幾乎和 JSX 同樣,只是咱們須要以略微不一樣的方式插入變量;可是,大部分區別都是很細節的地方,若是你想要展現如何不使用任何構建工具來使用 React,這個工具就很方便。

類 Lisp 語法

它的核心思想和 hyperscript 很相似,但它採用了一個很優雅的方式,值得一看。現現在,有不少相似的幫助庫,因此到底選擇哪一個也因人而異;而它們都有可能能給你的項目帶來些靈感。

ijk 這個庫的思路是隻用數組來寫模版,並將位置做爲參數。這樣寫的優點在於你不須要老是寫 h(是的,有時候總寫 h 也會讓人以爲很冗餘!)。以下是一個使用案例:

function render(structure) {
  return h('nodeName', 'attributes', 'children')(structure)
}
class A extends React.Component {
  render() {
    return render([
      'div', { className: 'class', onClick, some}, [
        'something',
        ['div', 'something else']
      ]]);
  }
}
複製代碼

總結

這篇文章並非建議你不使用 JSX,也不是說 JSX 有什麼很差。可是你可能會好奇若是不用它,你要怎麼寫代碼,還有你的代碼可能會是什麼樣子,本文的目的就只是回答了這個問題。

若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索