為什麼你該認識前端開發框架— 以React 為例
在跟 React 搏鬥了三周之後,那些關於我認識的 React
從前端 HTML、CSS、JS 到後端 PHP + Express 的基礎訓練後,終於來到最後一站,現代開發框架:React,以下會用 Huli 常常拿來討論技術的架構下去討論我所認識的 React
這個技術出現以前是什麼樣子?
那時候碰到什麼樣問題?
這個技術的出現如何解決問題?
所以這項技術應該如何使用?
跟以前的解法比起來,差別在哪裡?有什麼優缺點?
那就馬上開始吧!
React 出現以前是什麼樣子
其實課綱上的順序變是 React 出現以前的開發流程。透過
document.querySelector()
去選擇 DOM 裡面的內容,然後直接修改 DOM 裡面的內容。(延伸閱讀:從課綱看前端開發歷程、零基礎的小明要如何成為前端工程師?)
那這樣會出現什麼問題嗎?
1. 效能較慢
我們先看到底下這張瀏覽器的渲染步驟,效能上可優化之處變顯而易見。
基本上渲染會先經過以下幾個步驟
- HTML 解析出 DOM tree
- CSS 解析出 CSSDOM tree
- 合併以上兩個檔案 Merging 成 Render Tree 再畫出來
所以當我們使用 querySelector 直接修改 DOM 之後,以上的流程就會重來一遍,簡單來說,如果我們隨便改一個地方都要全部重跑,那效能上肯定不是快的。(延伸閱讀:[CSS] Reflow 及 Repaint 是什麼?)
2. 難以維護
由於需要透過 JavaScript 處理互動的內容,勢必會把 HTML、CSS、JavaScript 混在一起,導致維護困難
3. 畫面 ( UI ) 跟狀態保持一致
但如果真要說,這一點才算是真正大框架時代到來的主因。在 JQuery 時代,我們需要手動同步狀態跟畫面。如果我們在跟伺服器來回交互的時候還需要再次考慮畫面跟狀態是否保持一致,那因為這個原因又會需要犧牲效能。
所以簡單一句使用框架最大的目的就是為了確保畫面跟狀態都能保持一致
那 React 的出現如何解決以上這些問題?
- Virtual DOM 的實現
我們由上述知道直接操作 DOM 會造成效能上的浪費。於是透過 JS 的方式將原先的 DOM parse/traversal 為 JavaScript 物件暫存在某個地方。並且比較與原先的 DOM 差別後僅新增修改的部分。於是乎修改一個地方就要全部重跑一次的問題就解決了。
2. 畫面 ( UI ) 跟狀態一致性問題
以往我們都要手動修改資料,並且還要手動修改畫面。以 To-do List 來說。
假如我們新增 Todo-List 1,就要先到後端新增這筆資料,然後在畫面上再次新增 Todo-List 1 ,這樣新增待辦事項才算完成。
而 React 採用的方式是用 State 的方式保存資料,並且透過資料叫出畫面。於是現有的畫面都是直接從後端抓已經存在資料庫的資料,所以不會有那種明明已經把資料存到資料庫了,卻在前端畫面沒有新增的狀況。
所以這項技術應該如何使用?
基本上最核心的觀念就是 React 由 Component 組成,並透過 State 存取資料
譬如今天要做一個評論功能的應用,就可以切成四個 Componet,分別為 CommentApp、CommentInput、CommentList、Comment。
而其層級關係如下
將 Comment Input 打包好丟出來好讓 CommentApp 可以使用(Comment List作法亦然)
import React from 'react'
const CommentInput = () => {
return(
<div> 這裡是 Comment Input </div>
)
} export default CommentInput
在 CommentApp 裡面將 Commet Input 與 Comment List包起來
import React, { Component } from 'react'
import CommentInput from './CommentInput'
import CommentList from './CommentList' const CommentApp = () => {
return(
<div>
<CommentInput />
<CommentList />
</div>
);
}export default CommentApp;
並且簡單來說可以知道我們需要用戶名跟評論內容,於是將 user 跟 content 用 State 儲存內容,基本用法是
const [example, setExample] = useState(‘預設值’)
import React, { useState } from 'react'
import CommentInput from './CommentInput'
import CommentList from './CommentList'const CommentApp = () => {
const [user, SetUser] = useState('');
const [content, SetContent] = useState('');
return(
<div>
<CommentInput />
<CommentList />
</div>
);
}
export default CommentApp;
我們把 CommentInput 直接套進來可以看得更清楚,我們今天直接把輸入框套入預設值
import React, { useState } from 'react'
import CommentList from './CommentList'const CommentApp = () => {
const [user, SetUser] = useState('');
const [content, SetContent] = useState('');
return(
<div>
<input value={user} />
<input value={content} />
<CommentList />
</div>
);
}
export default CommentApp;
再來設定輸入(onChange)的時候要更改值,以 User 為例,並且在更改的時候使用 SetUser 存入更改後的值
import React, { useState } from 'react'
import CommentList from './CommentList'const CommentApp = () => {
const [user, SetUser] = useState('');
const [content, SetContent] = useState('');
const handleInputChange = (event) => {
const user = event.target.value;
setUser({ user });
} return(
<div>
<input value={user} onClick={handleInputChange}/>
<input value={content} />
<CommentList />
</div>
);
}
export default CommentApp;
基本上就大功告成囉,然而今天是簡化將 Comment Input 寫在一起,如果要另外寫在其他檔案的話,就得用 Prop 這個參數將 State 傳入其他檔案囉。所以像 user 或 content 會以 State 的方式存在 CommentApp,再以 Prop 的方式傳到子檔案如 Comment Input 或 Comment List。
最後一哩路則是會看到咱們的 Comment App 最後也打包出去了,那其實就是被引入 index.js 做渲染,可以看到 ReactDOM.render 裡面基本就是上面所說先複製成 Virtual DOM 再去比較差異插入的過程,所以底下的檔案要是有 State 的更改,就會重新觸發 Render,再次進行比較的過程。
import React from 'react';import ReactDOM from 'react-dom';import CommentApp from './CommentApp';ReactDOM.render(<CommentApp />,document.getElementById('root'));
那基本上 React 就是以這個為基礎開發!有了這個觀念之後就可以上手 React 拉!
結語
剛開始還是習慣使用 document.querySelector 去選擇 DOM,後來學了 JQuery 之後想說天下太平。沒想到最後在課程尾端殺出 React 這個程咬金,完全跟以往的開發思維不同。從直接操作 DOM 到修改 State 真的是個很大的轉換,再來就要學習 Redux 了,到時候再整理一篇 React-Redux 的修習心得吧!