iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 22
0
Modern Web

關於React,那些我不知道的系列 第 22

如何做一個 銀行/分行的選單 selectorFamily

  • 分享至 

  • xImage
  •  

回到 selectorFamily 提供的當初的情境。

回顧

Codesandbox demo
簡單假設我們的api格式

取得銀行

export function getBanks() {
  return [
    { id: 0, name: "中國信託" },
    { id: 1, name: "玉山銀行" },
    { id: 2, name: "王道銀行" },
    { id: 3, name: "富邦銀行" },
    { id: 4, name: "國泰銀行" }
  ];
}

取得分行

export function getBranches(id) {
  let branches = [
    [
      { id: 0, name: "中信分行1" },
      { id: 1, name: "中信分行2" },
      { id: 2, name: "中信分行3" },
      { id: 3, name: "中信分行4" }
    ],
    ........
    [
      { id: 16, name: "國泰分行1" },
      { id: 17, name: "國泰分行2" },
      { id: 18, name: "國泰分行3" },
      { id: 19, name: "國泰分行4" }
    ]
  ];
  return branches[id];
}

UI

從 UI 下手去思考,為了符合需求,我們建立了兩組 select / option ,一組是銀行選項,另一組是根據該銀行顯示分行的選項。

    <>
      銀行:
      <select onChange={updateBank}>
        {bankOptions.map((bank) => (
          <option key={bank.id} value={bank.id}>
            {bank.name}
          </option>
        ))}
      </select>
      <br />
      分行:
      <select onChange={updateBranch}>
        {branchOptions.map((branch, index) => (
          <option key={branch.id} value={branch.id}>
            {branch.name}
          </option>
        ))}
      </select>
    </>

Recoil State

因此回過頭來思考,我們需要
1.一個狀態來儲存所有銀行的選項
2.一個狀態來儲存當前被選到的銀行
3.一個狀態儲存當前被選到的銀行底下分行的選項
4.一個狀態儲存當前分行的選項,但是切換銀行時,我們希望這個分行也會被 Reset。

1. Bank option

export const bankOptionState = atom({
  key: "bankOption",
  default: getBanks()
});

2. Current Bank ID

儲存當前銀行ID

export const currentBankIDState = atom({
  key: "currentBankID",
  default: 0
});

3. Branch Option

首先我們希望所有的分行資訊都能被 Recoil 儲存,但又不希望開很多key 來儲存很多 state (比如 bank1branchOption、bank2branchOption、bank3branchOption、bank4branchOption),因此我們透過 selectorFamily 將所有 branch 都用同一個 key branchOption 儲存起來,我們在帶入 bank id 來取得對應的 branch。

export const branchOptionState = selectorFamily({
  key: "branchOption",
  get: (bankID) => ({ get }) => {
    const branches = getBranches(bankID);
    return branches;
  }
});

4.Current Branch ID

儲存當前分行ID

export const currentBranchIDState = atom({
  key: "currentBranchID",
  default: 0
});

回到我們 Component

1

首先需要取讀 currentBankID, currentBranchID 再據此渲染對應的option

function SomeUserForm() {
  const [currentBankID, setCurrentBankID] = useRecoilState(currentBankIDState);
  const [currentBranchID, setCurrentBranchID] = useRecoilState(
    currentBranchIDState
  );
  const updateBank = ({ target: { value } }) => {
    setCurrentBankID(value);
  };
  const updateBranch = ({ target: { value } }) => {
    setCurrentBranchID(value);
  };

2

接著取得對應的 option,而這邊的 branchOptions ,是透過selectorFamily所建立,可以傳入參數銀行ID,因此可根據當前銀行ID 傳回對應的分行 option

  const bankOptions = useRecoilValue(bankOptionState);
  const branchOptions = useRecoilValue(branchOptionState(currentBankID));

3

接著完成我們的元件

    <>
      銀行:
      <select value={currentBankID} onChange={updateBank}>
        {bankOptions.map((bank) => (
          <option key={bank.id} value={bank.id}>
            {bank.name}
          </option>
        ))}
      </select>
      <br />
      分行:
      <select value={currentBranchID} onChange={updateBranch}>
        {branchOptions.map((branch, index) => (
          <option key={branch.id} value={branch.id}>
            {branch.name}
          </option>
        ))}
      </select>
    </>

4

但目前我們的銀行改變,還不會跟著修改分行ID,因此我們加入一組useEffect,讓銀行ID改變時,也改變分行

  useEffect(() => {
    setCurrentBranchID(branchOptions[0].id);
  }, [currentBankID]);

Codesandbox demo


上一篇
狀態管理的救星?! Recoil 想用參數來切換 state 怎麼辦? ( selectorFamily ) 2
下一篇
狀態管理的救星?! Recoil 來自遠方的狀態,如何處理Async State? (2)
系列文
關於React,那些我不知道的30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言