iT邦幫忙

2025 iThome 鐵人賽

DAY 30
0
Modern Web

重溫 React 官方文件回到最初的起點系列 第 30

Day 30 - 用 React 的方式去思考

  • 分享至 

  • xImage
  •  

今天是鐵人賽的最後一天,剛好在昨天也介紹完了官方文件的 管理 State 篇章。後面還剩 逃脫出口 出口這個篇章沒介紹完,主要的內容會是對 React 以外的系統進行控制和同步,會用到 hooks: useRefuseEffect 等。也是十分重要的篇章,所以之後應該也會花時間把它補完。

今天想介紹的是其實是官方文件放在比較前面的文章,但我覺得要先把一些 React 的用法先介紹完再來介紹這篇會比較好。標題是:用 React 的方式去思考 - Thinking in React

這個篇章會介紹如何用 React 的思考方式去設計一個頁面 UI,會從一個簡單的 mockup 開始,一步步用 React 完成 UI。

從 mockup 開始

正常來說,我們開發的時候會拿到一份能獲得呈現資料的 API 跟設計師設計出來的畫面 mockup,mockup 就有點像是畫面的基本架構,還有沒把完整外觀呈現出來。我們會藉著 mockup 把畫面拆成可能的 React components。這次文章也是使用官方文件的範例。

第一步:將 UI 拆解成一層層的 component

通常我們在拆解的時候,會希望一個 component 專心做一件事,如果他會需要同時處理多個事物,那代表他可能可以把它拆成更細。Component 越細就越有機會被拿來重複利用。用文章的例子就會拆成像是:

https://ithelp.ithome.com.tw/upload/images/20251014/201630248638CRZ788.png

會把 UI 分成:

  1. FilterableProductTable(灰色)是整個應用程式的容器。
  2. SearchBar(藍色)用來接收使用者的輸入。
  3. ProductTable(淡紫色)會根據使用者的輸入顯示並篩選清單。
  4. ProductCategoryRow(綠色)用來顯示每個類別的標題。
  5. ProductRow(黃色)顯示每筆產品資料的一列。

拆解完後就可以把這些 component 分層:

  • FilterableProductTable
    • SearchBar
    • ProductTable
      • ProductCategoryRow
      • ProductRow

第二步:使用 React 建立靜態版本

有了基本架構後,我們就可以試著用 React 把這些 component 先刻出一個靜態的版本。靜態的意思就是 UI 不會透過互動修改資料,只透過固定的資料呈現畫面。在這階段資料會只透過 props 在 component 之間傳輸,不會用到任何的 state,可以透過我們剛剛的分的層級來從上到下把 component 的位置刻出來,也可以從下到上,先把層級比較低的 component 先刻出來再去拼湊上層的 component。這個就比較看個人喜好。

第三步:找到最小但最完整的 UI 狀態

把靜態的 UI 寫出來後,接下來就要把互動加進去,這就會需要用到之前學的 React state。在前面的篇章已經介紹滿多如何設計 state 的思考邏輯,這邊再整理一下:

  • 它會隨時間變化保持不變嗎?會的話,那它就不是 state。
  • 它是透過 props 從 parent 傳進來的嗎?是的話,那它就不是 state。
  • 你能根據 component 中現有的 state 或 props 計算出它嗎?可以的話,那它絕對不是 state!

而我們在範例會有需要使用到的資料有:

  1. 原始的產品清單
  2. 使用者輸入的搜尋文字
  3. Checkbox 的勾選狀態
  4. 篩選後的產品清單

照著剛才的邏輯一個一個檢查:

  1. 原始的清單會從 API 取得後透過 props 傳遞,所以不會是 state
  2. 會根據使用者輸入的內容隨時間改變,且不能被其他資料算出來,所以是 state
  3. 根據使用者確定是否有勾選,也會隨時間改變,也不能被算出來,所以是 state
  4. 可以被原始清單進行 filter() 過後產生出來,所以不需要當作 state

最後就會只留下紀錄使用者輸入文字的跟 checkbox 狀態的 state。

第四步:辨識 state 應該放在哪裡

確定好會使用到哪些 state 後,就要思考要把 state 放在哪邊,會有以下步驟:

  1. 先找出所有可能會需要用到 state 的 components
  2. 找到這些 components 最近的共同 parent component
  3. 決定 state 放在哪邊,因為剛剛有找到共同的 parent,所以通常會直接放在那邊,但也有可能會再往上一層處理(未來可能會有中間其他層使用),又或是都沒找到適合的 component,也可以建立一個新的 component 來處理 state。

照著上面的步驟走:
1.

  • ProductTable 需要知道搜尋文字與 checkbox 狀態來篩選內容
  • SearchBar 需要顯數輸入的搜尋文字與使用者勾選狀態
  1. 搜尋文字跟 checkbox state 的共同 parent 會是 FilterableProductTable
  2. 把 state 存放在 FilterableProductTable

FilterableProductTable component 裡就可以寫上

function FilterableProductTable({ products }) {
  const [filterText, setFilterText] = useState('');
  const [inStockOnly, setInStockOnly] = useState(false);
  
  return (
    <div>
      <SearchBar 
        filterText={filterText} 
        inStockOnly={inStockOnly}
      />
      <ProductTable 
        products={products}
        filterText={filterText}
        inStockOnly={inStockOnly}
      />
    </div>
  )
}

第五步:加入反向資料流

找到 state 放入位置跟需要透過 props 傳遞的 component 後,我們還需要透過 handlers 來更新 state 不然畫面不會具有互動性,這時候就要使用剛剛在 FilterableProductTable component 宣告的 state 們的 setter 向下傳入給 child components 使用。這樣才能透過傳下去的 setterhandler 裡觸發更新,反向的更新上層的 state。

<SearchBar 
  filterText={filterText} 
  inStockOnly={inStockOnly}
+ onFilterTextChange={setFilterText}
+ onInStockOnlyChange={setInStockOnly}  
/>

這樣整個簡單的 UI 就可以順利地完成了。雖然還可以再多改善,像是可以再加入 CSS 讓畫面外觀更好看,或是把 ProductTable 裡的 component 做更細的處理,但主要概念還是上面介紹的步驟,可以讓我們在設計 React 應用程式上更為流暢。在開發的時候遇瓶頸也可以試著重新照著剛剛介紹的步驟再順過一次。

小結

這次 30 天的鐵人賽就到這邊告一個段落,感謝大家耐心地看完。這次真的因爲時間很趕,所以各篇章篇幅都沒拿捏的恰當,還有好幾天是壓線過關的,其實中間有幾度差點要放棄,算是跌跌撞撞的寫完了。

前面提到還尚未介紹完的篇章,會持續補完,畢竟這次參賽的主要目的是自己的複習心得,要把全部篇章唸完才算完整。

最後再次感謝觀看的大家,如果有任何問題與建議都歡迎告訴我,之後的篇章見,晚安。


上一篇
Day 29 - 使用 Reducer 跟 Context 進行擴展
系列文
重溫 React 官方文件回到最初的起點30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言