iT邦幫忙

2023 iThome 鐵人賽

DAY 4
0
Modern Web

30天React練功坊-攻克常見實務/面試問題系列 第 4

30天React練功坊-攻克常見實務/面試問題 Day4: Way too many state in a component

  • 分享至 

  • xImage
  •  
tags: ItIron2023 react

前言

昨天我們配合了兩個hook去理解react render的機制以及一些useState & useEffect的眉眉角角,其中我們有提到利用物件作為state初始值的情況,今天我們就針對這一點來看一個實務常見的情況吧!

本日題目

馬上就開始吧,請觀察這個codesandbox內的程式碼。

day4-demo-image

首先,這份程式碼並沒有任何的錯誤發生,所有的行為也如我們預期,輸入後點擊送出可以看到state有正確的被更新,要送出的payload並沒有任何不對,不過仔細看一下程式碼的部分你會發現有許多重複的部分,這還只是僅有三個欄位的情況,現實的userData往往更為複雜,若你每個編輯表單都要這樣搞,我相信會有許多很有趣的事情發生,請觀察以下的程式碼並優化,你的解法有著以下的前提

  1. 能應付更多的欄位以及避免重複程式碼的產生
  2. 你可以去更動html的結構,例如元素的屬性等,但最終在submit送出的資料需要相同
export default function App() {
  const [name, setName] = useState("");
  const [email, setEmail] = useState("");
  const [age, setAge] = useState("");

  const handleNameChange = (e) => {
    setName(e.target.value);
  };

  const handleEmailChange = (e) => {
    setEmail(e.target.value);
  };

  const handleAgeChange = (e) => {
    setAge(e.target.value);
  };

  const handleSubmit = () => {
    console.log("Submitted User Info:", { name, email, age });
  };

  return (
    <div className="App">
      <h1>Way too many state in a component</h1>
      <form>
        <label>
          Name:
          <input type="text" value={name} onChange={handleNameChange} />
        </label>
        <br />
        <label>
          Email:
          <input type="email" value={email} onChange={handleEmailChange} />
        </label>
        <br />
        <label>
          Age:
          <input type="text" value={age} onChange={handleAgeChange} />
        </label>
        <br />
        <button type="button" onClick={handleSubmit}>
          Submit
        </button>
      </form>
    </div>
  );
}

解答與基本解釋

這次的問題也是很常見到的情況,多半會出現在表單的新增或是編輯,比方說使用者的註冊或是偏好的更新等等。當然你完全不處理也是沒問題的,畢竟它並沒有真的造成什麼大問題,但就像我說的,要是欄位不斷增加,你整個程式碼的可讀性自然會變得更差一些。

很多人看到這個問題首先的想法就是先針對state下手,畢竟題目都說了Way too many state,所以第一步會是先用一個更大包的物件來處理,比方說userInfo這樣的state

const [userInfo, setUserInfo] = useState({ name: '', email: '', age: '' });

這樣的方向是完全正確的,但問題在於後續的onChange handler處理,如果你還是一個一個hanlder去處理每一個input欄位,例如像是這樣

const handleNameChange = () => {
  setUserInfo({
    ...userInfo,
    name: 'John'
  });
};

const handleEmailChange = () => {
  setUserInfo({
    ...userInfo,
    email: 'john@example.com'
  });
};

const handleAgeChange = () => {
  setUserInfo({
    ...userInfo,
    age: '30'
  });
};

那麼實際上在欄位增加時你還是需要土法煉鋼去加上一個新的handler,並不是這麼理想,我個人會建議如果你要使用useState處理這類的情況,可以統一用一個handler處理,這麼一來欄位增加時也可以用更簡易的方式處理,例如像是這樣的統一hanlder

const handleChange = (e) => {
  const { name, value } = e.target;
  setUserInfo({
    ...userInfo,
    [name]: value
  });
};

在上方的例子中我們利用了動態的key值去處理,在此之前我們需要在原本的html結構上做一些調整,在每個input欄位加入對應的name attribute,這麼一來就可以在handler中取得需要的值作為動態key囉!

以email為例,原本是這樣的東西

<input type="email" value={email} onChange={handleEmailChange} />

你就必須動點手腳加上對應的name attribute以及修改value的傳遞方式,畢竟統一管理的話會變成使用userInfo這樣的欄位。

<input type="email" name="email" value={userInfo.email} onChange={handleChange} />

當然,若你今天的資料更為複雜一些且在某些情況下彼此依賴,那useState就不會是最適合的解法,這個問題我們就留到下次再討論吧!

總結

今天我們延伸了之前提過的useState以物件做初始值的情況並帶出了另一個實務上常見的問題,這類的情況很常出現在表單或是較為複雜的組件中,盡可能地去有效管理你的state可以大幅增加你程式碼可讀性並避免一些維護上的問題,但這並不是告訴你所有的state都需要用一個大物件統一管理,我們之後會再探討類似的情況,今天就先到此為止!明天見!

本文章同步發布於個人部落格,有興趣的朋友也可以來逛逛~!


上一篇
30天React練功坊-攻克常見實務/面試問題 Day3: Uncaught TypeError: Cannot set properties of undefined
下一篇
30天React練功坊-攻克常見實務/面試問題 Day5 An unexpected "0" in the page while doing condition rendering
系列文
30天React練功坊-攻克常見實務/面試問題30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
lijun
iT邦新手 4 級 ‧ 2023-12-06 13:02:03

作者您好
中間在統一hanlder的部分我看不太懂
上下不太連貫

這樣的統一hanlder

const handleChange = (e) => {
  const { name, value } = e.target;
  setUserInfo({
    ...userInfo,
    [name]: value
  });
};

下面修改html的結構是不是就要寫成

<input type="text" name="name" value={userInfo.name} onChange={handleChange}/>

lijun 你說得完全正確~這部分確實是我打得太過於簡略了,我當時的想法僅是打算跟讀者表示說需要去修改下方input欄位的程式碼,因此沒有提供修改後程式碼的樣子,不好意思!希望沒有造成你太多的困惑,我稍後會做修改,謝謝你提出!

我要留言

立即登入留言