簡評:現代 JavaScript 框架的出現最主要是解決哪一個問題?這篇文章很好的解釋了這個問題。
我見過許多人盲目地使用像 React,Angular 或 Vue.js 這樣的現代框架。這些框架提供了許多有趣的東西,一般人們會忽略這些框架存在最主要的緣由,這些緣由不是:javascript
這些都不是最本質的緣由,最本質的緣由是保持 UI 和狀態同步並不容易。html
UI 和 狀態同步難在哪?java
假如,您正在構建一個 Web 應用程序,用戶能夠填寫他人的 email 地址來發起邀請。而且邀請列表有兩種狀態:git
嘗試使用純 JavaScript 實現這種功能github
源碼和效果能夠到參考:codepen。瀏覽器
index.html 代碼服務器
<html> <body> <div id="addressList"> <form> <input> <p class="help">Type an email address and hit enter</p> <ul> </ul> </form> </div> </body> </html>
JS 代碼babel
class AddressList { constructor(root) { // state variables this.state = [] // UI variables this.root = root this.form = root.querySelector('form') this.input = this.form.querySelector('input') this.help = this.form.querySelector('.help') this.ul = root.querySelector('ul') this.items = {} // id -> li element // event handlers this.form.addEventListener('submit', e => { e.preventDefault() const address = this.input.value this.input.value = '' this.addAddress(address) }) this.ul.addEventListener('click', e => { const id = e.target.getAttribute('data-delete-id') if (!id) return // user clicked in something else this.removeAddress(id) }) } addAddress(address) { // state logic const id = String(Date.now()) this.state = this.state.concat({ address, id }) // UI logic this.updateHelp() const li = document.createElement('li') const span = document.createElement('span') const del = document.createElement('a') span.innerText = address del.innerText = 'delete' del.setAttribute('data-delete-id', id) this.ul.appendChild(li) li.appendChild(del) li.appendChild(span) this.items[id] = li } removeAddress(id) { // state logic this.state = this.state.filter(item => item.id !== id) // UI logic this.updateHelp() const li = this.items[id] this.ul.removeChild(li) } // utility method updateHelp() { if (this.state.length > 0) { this.help.classList.add('hidden') } else { this.help.classList.remove('hidden') } } } const root = document.getElementById('addressList') new AddressList(root)
這段代碼很好的說明了使用純 JavaScript 實現一個有點小複雜的 UI 所須要的工做量。app
在示例中,靜態結構在 HTML 中建立,動態內容使用 JavaScript 來建立。這種方式有幾個問題:框架
構建 UI 的 JavaScript 代碼可讀性不高,咱們用兩個不一樣的部分來定義 UI。咱們可使用 innerHTML來讓代碼更容讀,可是這樣效率不高,並且容易引起跨站腳本漏洞。咱們也可使用模板引擎,可是若是從新生成大的 DOM 的子節點又會遇到兩個問題:效率不高,一般須要從新鏈接 event handler。
但這都是小問題,最主要的問題是:咱們須要在狀態變動的時候更新 UI。每一次狀態出現變動咱們都須要使用大量的代碼來更新 UI。上面的例子咱們更新狀態是用了兩行的代碼,可是更新 UI 卻耗費了 13 行代碼(儘管這個 UI 並不複雜)。
它不只編寫起來複雜並且還很脆弱。想象一下,咱們須要實現將列表於服務器同步的功能。咱們須要將本地數據和服務器發來的數據進行比較。而且須要點對點的對每一個變動同步到 DOM 節點中。若是這個過程當中有每一步出現差錯都直接致使 UI 同步失敗。
所以,維護 UI 與數據同步須要編寫大量繁瑣,脆弱和脆弱的代碼。
聲明式 UI 解決方案
它是否是社區,它不是工具,也不是生態系統,也不是第三方庫......
到目前爲止,這些框架提供的最大的改進是實現應用狀態和 UI 同步。
咱們只須要定義一次 UI,沒必要編寫爲每一次動做編寫 UI。相同的狀態總能獲得相同的 UI 輸出(狀態和 UI 同步,狀態變動後會自動更新 UI)。
原理
有兩個基本策略:
和 Web Component 比較?
不少時候人們將 React,Angular 和 Vue.js 和 Web 組件進行比較。不少人不理解這些框架提供的最大好處:保持 UI 和狀態同步。而 Web 組件並不提供內容,它是一套規範,以便開發者能夠自由建立可重用的元素。因此單純使用 Web Component + 純 JavaScript 仍然須要手動保證狀態同步,要實現高效易維護的 UI 還須要使用 現代 JavaScript 框架。
本身實現
本身實現一個相似的功能,可以加深對原理的理解。咱們嘗試使用 虛擬DOM (而不是直接用第三方框架)實現一個相似 React 的框架,來重寫剛剛的 demo。
下面是咱們 Framework 的核心部分,表明全部組件的基類:
下面是基於 Component 重寫的郵箱邀請的應用(藉助 babel 變換來支持 JSX)這裏是源碼:
如今的 UI 是聲明性的,並且咱們沒有直接使用任何框架。咱們能夠實現以任何方式更改狀態的邏輯,而且不須要額外編寫 UI 同步的代碼。
原文: The deepest reason why modern JavaScript frameworks exist