iT邦幫忙

1

React雜談#1 React-Hook-Form - 建立快速的React表單

  • 分享至 

  • xImage
  •  

有使用過React的同學都知道,用React做輸入控制的時候, 通常做法是建立一個input的state, 具體如下:

import { useState } from "react";

export default function Form() {
  const [surname, setSurname] = useState("");
  const [firstName, setFirstName] = useState("");
  const [age, setAge] = useState(0);
  const onFormSumbit = (e) => {
    e.preventDefault();
    console.log("Form Submitted");
    const formData = new FormData(e.target);
    for (const pair of formData.entries()) {
      console.log(`${pair[0]}: ${pair[1]}`);
    }
  };

  //every single rendering trigger the following code once
  console.log("Form rendered");
  return (
    <form onSubmit={onFormSumbit}>
      <h1>Using Pure React</h1>
      First Name:
      <input
        onChange={(e) => {
          setFirstName(e.target.value);
        }}
        name="firstName"
        value={firstName || ""}
      />
      <br />
      Surname:
      <input
        onChange={(e) => {
          setSurname(e.target.value);
        }}
        name="surname"
        value={surname || ""}
      />
      <br />
      Age:
      <input
        onChange={(e) => {
          setAge(e.target.value);
        }}
        name="age"
        value={age || ""}
        type="number"
      />
      <br />
      <input type="submit" />
    </form>
  );
}

事實上React的官方best practise也是這樣的。 但是當製作有多個輸入項的表單時, 事情就麻煩了。 不單每個輸入項都要設定一個State給他, 代碼變得臃腫難閱讀。 更嚴重的是, 每次用戶填寫表單的時候, 即使是再微小的改動, 也會觸發整個表單的渲染(rendering)。 每增加一個字, 渲染一次,每刪除一個字,渲染一次, 那樣前端的效率會大大受到影響。

傳統React填表過程觸發多次渲染

解決這類問題的辦法有很多,例如我們可以使用useEffect去優化渲染時的效率,但這裡有一個更好的工具去完完全全避免這因為input而產生的渲染,這就是今天要介紹的React-Hook-Form。
以下是一個使用React-Hook-Form重新製作的表單:

import { useForm } from "react-hook-form";

export default function HookForm() {
  const { register, handleSubmit } = useForm();
  const onFormSumbit = (formObj, e) => {
    e.preventDefault();
    console.log("Form Submitted");
    const formData = new FormData(e.target);
    for (const pair of formData.entries()) {
      console.log(`${pair[0]}: ${pair[1]}`);
    }
  };

  //every single rendering trigger the following code once
  console.log("Form rendered");
  return (
    <form onSubmit={handleSubmit(onFormSumbit)}>
      <h1>Using React-Hook-Form</h1>
      First Name:
      <input {...register("firstName")} />
      <br />
      Surname:
      <input {...register("surname")} />
      <br />
      Age:
      <input {...register("age")} />
      <br />
      <input type="submit" />
    </form>
  );
}

你會看到與傳統表單最大的分別是已經沒有了setState, 取而代之是一次useForm, 以及在input裏面的register函數。 
再來看看它在填寫表單時的渲染次數

React-hook-form只觸發1次渲染

什麼!只有1次!?對, 這就是React-Hook-Form的神奇魔法。它為什麼做到如此強大的功能呢, 關鍵就在於一個字:ref

<input {...register("firstName")} />

這個register函數會返回一個包含4個屬性(attribute)的物件(object),那4個屬性分別是name,onChange,onBlur,以及ref。這裡的name會是我們傳入register的第一個參數,通常是輸入項的名稱。onChange,onBlur 傳入對應的event handler。最後的ref屬性提供了一個接口,讓React-Hook-Form能繞過React的Virtual Dom,訪問input真實的DOM nodes。

因為React-Hook-Form 在最後提交的時候才通過ref取得DOM nodes的數值,input的數值根本沒有綁定在React裡。所以我們改變input的value,也不會觸發渲染。

總結

對比單純用state做的表單,React-Hook-Form提供了一個簡單易用的介面,除了讓setup變得更快,更解決了輸入渲染的問題,在建立多個或者複雜表單時會很有用。
React-Hook-Form亦提供了諸多如數據驗證等等其他表單常見的功能,十分推介大家嘗試這個Library。


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
AndrewYEE
iT邦新手 3 級 ‧ 2023-02-08 20:04:01

好耶!

我要留言

立即登入留言