iT邦幫忙

2022 iThome 鐵人賽

DAY 9
0
Modern Web

前端技能樹的十萬個為什麼系列 第 9

Day 9 - 為什麼要用 Controlled Component

  • 分享至 

  • xImage
  •  

前言

如果有讀過 React 官方文件,應該會看到這一篇文章,除了介紹表單元件有兩種(Uncontrolled 與 Controlled),還特別提到:

在大多數的情況下,我們推薦使用 controlled component 來實作表單。

如果只注重寫 code,很容易看到這就會告訴自己說:

既然官方都這樣建議了,那我就直接用 controlled component 吧!

但更進一步去想的話,如果有東西可以完勝另一個東西,那也用不著「建議」了,直接告訴我「只能」用 controlled component 就好啦~顯然這中間有些東西值得我們來看看囉!

先想一下

  • Uncontrolled 與 Controlled Component 的差別在哪?
  • Uncontrolled 與 Controlled Component 各自的優缺點是什麼?
  • Uncontrolled 與 Controlled Component 各自適合什麼情境?

Uncontrolled 與 Controlled Component 的差別在哪?

首先肯定是要先搞懂這兩者的定義是什麼,後續的討論才有意義。由於兩者名字都太長了,容我下文直接用簡稱:

非受控元件:Uncontrolled Component
受控元件:Controlled Component

非受控元件

就像傳統的 HTML 表單輸入元件:

<input type="text" />

當使用者在這個 input 輸入文字,主要由 input 的 DOM 本身來儲存 value,當按下送出表單的按鈕時,會再透過抓取 DOM 節點的方式(比如事先塞一個 ref,或者 jQuery 也可以辦到),取得節點後再取得裡面存的 value。

將 value 存在 DOM 節點內」,我們無法特別去控制它,因此叫做「非受控」。

受控元件

受控元件可以參考官方文件,簡單來說,如果輸入欄位的 value property 與 onChange callback function,是由元件提供的(而不是存在 DOM 節點自己處理的),那就是受控元件,比如:

const [name, setName] = useState("Allen");
const handleNameChanged = (e) => {
  setName(e.target.value);
};

return (
  <input type="text" value={name} onChange={handleNameChanged} />
);

上面的例子可以看到,重點在於比起非受控元件,我們多指定了 valueonChange 的值給它,而這兩個背後都是由元件本身的 state 來控制,所以即便使用者從沒輸入過 Allen 這個單字,我依然可以透過 state,直接將單字塞到這個欄位上。

這邊用 state 來控制只是大多數的情況,你也可以從 props 或 context 等地方取值後塞給 value,反正只要指定了 value 與 onChange,就會是受控元件。

另外,value 只是代表這個欄位儲存的值,它不一定叫做 value,比如 radio type 就會用 checked

<input type="radio" checked={false} />

Uncontrolled 與 Controlled Component 各自的優缺點是什麼?

優點

  • 非受控元件的優點是非常純粹(不添加任何外來物質),只要把值乖乖放在自己身上,不用隨時更新到 state 上,因此整體效能來說是較好的
  • 受控元件的優點是,對於表單的掌控能力提高,因為隨時可以知道每個欄位即時的數值,就可以做到像是「A 欄位如果選了什麼,B 欄位就怎樣」這種 UI 方面的交互關係。

缺點

  • 非受控元件的缺點是,對於表單掌控不即時,通常都是等按下「送出」按鈕時,一次性取得所有欄位的數值,意味著在按下「送出」之前,只能不斷手動取得各欄位的值,才能做到一些 UI 交互行為。
  • 受控元件的缺點是,每打一個字就會更新一次 state,同時伴隨畫面重新 render,更新畫面的頻率可能會過於頻繁,尤其如果元件內又包含很多元件,會每打一個字就 lag 一下,UX 扣分

Uncontrolled 與 Controlled Component 各自適合什麼情境?

非受控元件適合

  • 很單純的 form,使用者填完按下送出,才去取得各欄位的數值。
  • 很大量欄位的 form,避免每次輸入都修改 state 造成大範圍重新 render

受控元件適合

  • 需要即時對 form 檢查是否修改過(dirty)、格式驗證(validation)等情況
  • 需要即時取得 form 的 value 去連動影響其他欄位

結語

心智圖放大版

先自首一下,我就是文章開頭說的那位

既然官方都這樣建議了,那我就直接用 controlled component 吧!

當時我真的遇到所有 form 表單都用受控元件來處理,結果也真的在實務經驗上撞牆,因為我處理到了一個有幾百個欄位的 form 表單,每輸入一個字都像垂死的老人一樣,過了三秒才顯示在畫面上XD

當然我相信即便只用受控元件,依然有機會處理掉我遇到的 case,但那可能也是另一種解法了,這邊只是用自己的實務經驗,帶出「非受控元件也是很有價值的」!

且依然相信只要好好弄懂每個工具的定義、優缺點、適用情境,就能夠在正確的時候發揮出來

參考資料

controlled vs uncontrolled inputs react


上一篇
Day 8 - 為什麼要用 Context
下一篇
Day 10 - 為什麼要用 React Hook Form
系列文
前端技能樹的十萬個為什麼30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
Chiahsuan
iT邦新手 4 級 ‧ 2022-09-26 16:57:15

這篇的分析很棒噎!!!我也是直接想都不想就都全用 controlled component 的人(跪)

實務上有個小問題想向你確認:
對於幾百個欄位的 form 表單,在送出時還是會一次抓取值並做前端的格式驗證對嗎?謝謝~

ycchiuuuu iT邦新手 4 級 ‧ 2022-09-27 01:18:36 檢舉

對唷!無論受控與非受控元件,submit 前的驗證都是必要的~

受控元件是比較單純,因為都是即時掌握著 state,非受控元件則可以借助 react hook form 來做到類似的效果~

Chiahsuan iT邦新手 4 級 ‧ 2022-09-27 09:02:17 檢舉

好的~感謝:)

我要留言

立即登入留言