前端框架 React:初探 React 背後的運作方式

Hugh's Programming life
6 min readOct 25, 2019

--

JSX 的真面目

在使用 JSX 的時候,是需要 React 的,因為 JSX 原始的形式就是 React,可以透過下列的例子來得知。

import React, { Component } from 'react';
import Title from './Title';
class App extends Component {
render() {
return (
<div>
<Title />
</div>
)
}
}
export default App

title.js:

import React, { Component } from 'react';export default function Title() {
return <h1>hello</h1>
}

這會在畫面上印出一個 hello

這時候 title.js 看起來好像沒用到 React 那就把它拿掉試試看。

title.js:

export default function Title() {
return <h1>hello</h1>
}

結果會報錯:

這是因為不使用 JSX 的時候,原本的形式會長這樣:

title.js:import React, { Component } from 'react';export default function Title() {
return React.createElement('h1', null, `Hello`);
}

詳細官網有說明:

React 的渲染機制與 Virtual DOM

之前說每次只要 state 一改變,就會呼叫 render 來重新渲染畫面。

但像是我們之前利用 JQuery 模擬 React 的時候,是要先把資料清空,然後才 Render,所以有 100 個 item,假設刪除最後一個,就會整個畫面空清重新再來,這樣可能就會有效能問題。

那這樣我們在用 React 會不會有效能問題呢?實際上並不會

因為 React 在 render 的時候,並不會真的把畫面清空,然後才重新 render。React 中間其實還會有一個動作。

所以呼叫 render 之後產生的東西,可以稱為 Virtual DOM,最後才會變成 DOM。

這邊的意思可以看看一張圖

取自這邊:
React Virtual DOM vs Incremental DOM vs Ember’s Glimmer: Fight

會把這次的 DOM 跟下次的 DOM 做比較,其中的差異,才會去做改變。

這個 Virtual DOM 其實就是一個 JavaScript 的 Object

  render() {
return (
<div>
123
</div>
)

假設要 render 上面的 DOM,這個物件可能就會長得像下面那樣:

{
tag: 'div',
propsL null,
children: '123'
}

假設今天重新 render 成

  render() {
return (
<div>
456
</div>
)

新的 virtual DOM 可能就長這樣:

{
tag: 'div',
propsL null,
children: '456'
}

今天 React 就會把這兩個做比較

diff => 123 → 456

所以就只會變更這個部分。

所以以 todolist 的功能來說,當新增了一個之後,也是同樣的流程。

{
...
tag: 'div',
propsL null,
children: '99'
}
↓↓↓↓↓↓↓變成下方↓↓↓↓↓↓{
...
tag: 'div',
propsL null,
children: '99'
tag: 'div',
propsL null,
children: '100'
}
比較出差異之後:→ render 差異之處:
tag: 'div',
propsL null,
children: '100'

所以就可以直接使用 .setState() 去改變狀態,之後就會 call render,但這不代表真的就會去操作那個 DOM,只代表說 call render function 跟 React 說想要這樣子的畫面。

但實際上怎麼去 render 這個畫面,是 React 底層的機制在處理的,React 的工程師在這部份花了很大的心力。

整體而言,就是當我們改變 state 的時候,就會去呼叫 render,然後 React 會創造 virtual DOM,然後跟之前的 DOM 做比較,這兩者的差異才去應用到真的 DOM 上面。

Pure component 與 Immutable data

參考這篇文章:
React 性能優化大挑戰:一次理解 Immutable data 跟 shouldComponentUpdate

在這裡我是初學者,整篇我覺得最主要需要理解的觀念是 PureComponent 是什麼,以及 shallowEqual 的概念。

這樣才可以稍微看得懂這篇在說什麼。

簡單說 PureComponent 與 Component 的差異就在於有沒有先淺比較(shallowEqual)過,這個淺比較是可以透過比對第一層的長度來判斷是否需要 render 的。

所以最後文章的結論是如果 Component 常常會變動就不需要使用 PureComponent,而如果不會常變動就使用 PureComponent 即可。

也點出另外一個問題,因為淺比較只比較第一層,所以如果資料在很深(也可以說比較多層內)的地方怎麼辦?這樣就比較不了了。所以還要透過壓平的方式來把資料取出比較,所以說使用 PureComponent 會是比較麻煩的。

但是基本上會用到 PureComponent 的淺比較又是因為這樣比較節省資源,所以實際上並沒有差異到這麼多。

那麼就不用這麼急著使用 PureComponent 來優化了,可以等真的整個架構已經大這點差異,也會有影響的時候,再來使用即可。

收穫:

這整篇下來,我們理解到 JSX 的機制。然後是 render 的機制,實際上跟我想的不一樣。原來不是整個重新 render,而是會比較過之後才去 render 有差異的部份。

最後是篇比較困難些的文章,有很多名詞不明白,只能去查,查了之後才稍微比較理解到底是什麼意思。

讓我知道說原來 PureComponent 不用這麼早使用,等到整個程式碼變得有差到這部份也需要優化再來做即可。

在這裡也學到新的一點是關於 immutable data ,就是原來 .setState 會另外設立一個新的物件,原本的可能會保留做比較這樣子,我是覺得應該是跟 nextState 或是 prevState 會有關連吧。但這部份是我的猜測,之後應該會看到這部份的細節。

--

--

Hugh's Programming life
Hugh's Programming life

Written by Hugh's Programming life

我是前端兼後端工程師,主要在前端開發,包括 React、Node.js 以及相關的框架和技術。之前曾擔任化工工程師的職位,然而對電腦科技一直抱有濃厚的熱情。後來,我參加了轉職課程並開設這個部落格紀錄我的學習過程。於2020年轉職成功後,我一直持續精進技能、擴展技術範疇跟各種對人生有正面意義的學習,以增加我的工作能力。

No responses yet