🐙

子コンポーネントから親コンポーネントにstate経由で値を渡す

に公開

家計簿アプリを作っていて、全体の金額を表示している画面で、明細行を削除する場合、明細削除時に全体の金額からも数字を引く必要があります。

子コンポーネントの明細行の削除ボタン起因で、親コンポーネントの金額を更新します。制御はこちらの記事を参考にさせていただきました。
https://zenn.dev/stray/books/e3dbdf3f7aeac6/viewer/chapter8

現状とやりたいこと

  • 親で金額を表示している。
  • 金額は親で定義したinterfaceと変数で管理する。
  • 親から子にsetStateを渡す。
  • 子のボタン押下を起点に親の表示を更新する。

子コンポーネント

親からWalletという定義とsetStateを受け取る。行を削除したらsetStateを呼んで親の金額を更新する。(行の表示ロジックは省略)

child.tsx
interface Wallet {
  id: string
  name: string
  balance: number
}

export default function Journal(props: { wallet: Wallet; setWallet: any }) {
  interface Come {
    id: string
    amount: number
    createdAt: string
  }

  const deleteRow = (id: string, amount: number) => {
    props.setWallet(amount);
    setComeData(() => {
      return comeData.filter((Come) => {
        return Come.id !== id;
      })
    })
  }

  return (
    <div>
      <table className="border-separate border-spacing-2">
        <thead>
          <tr>
            <th>金額</th>
            <th>登録時間</th>
            <th>削除</th>
          </tr>
        </thead>
        <tbody>
          {comeData.map((item: Come, index) => (
            <tr key={index}>
              <td className="text-right">{item.amount}</td>
              <td>{item.createdAt}</td>
              <td>
                <button
                  type="button"
                  className="rounded bg-gray-200 p-2 transition-colors hover:bg-gray-300"
                  onClick={() => deleteRow(item.id, item.amount)}
                >
                  削除
                </button>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

親コンポーネント

子の削除ボタンが押下されたら balanceUpdate をcallして 金額:{walletData.balance} を更新する。

parent.tsx
export default function Page() {
  interface Wallet {
    id: string
    name: string
    balance: number
  }

  const [walletData, setWalletData] = useState<Wallet | null>(null)
  const balanceUpdate = (amount: number) => {
    setWalletData((prev) => {
      if (prev) {
        return { ...prev, balance: prev.balance - amount }
      }
      return prev
    })
  }

  return (
    <div>
      <h1>{walletData.name || "No Title Available"}に参加しているユーザー</h1>
      <h1>金額:{walletData.balance}</h1>
      <OutcomeForm wallet={{ id: walletData.id }} />
      <Journal wallet={walletData} setWallet={balanceUpdate} />
    </div>
  )
}

現代において画面全体をリロードすると時間がかかり、ユーザーがストレスを感じるので、変更箇所だけ更新する必要があります。コンポーネント間の値や関数の渡し方が実践できました。親と子どちらにも関数を書く事ができるので、明確に制限するなどして、一貫性のある仕組みを検討したい。

Discussion