简评:现代 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