1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【React】管理画面を作りながらReactを学ぶ(ライフサイクル関数/props/dynamic routing)

Last updated at Posted at 2022-03-07

まえがき

シリーズ形式の記事となります。今回は2つめ。
1. 【React】管理画面を作りながらReactを学ぶ(ChakraUI/コンポーネント化/react rooter v6)
2. 【React】管理画面を作りながらReactを学ぶ(ライフサイクル関数/props/dynamic routing)
3. 【React】管理画面を作りながらReactを学ぶ(ビルド)

前回の記事で作った管理画面

・レイアウト(ヘッダ/サイドメニュー)実装
・ルーティング(サイドメニューアイコンをクリックで画面切替)実装
image.png

今回の記事では「ライフサイクル関数」「props」を利用して、各画面が表示された時にそれっぽいデータをテーブル形式で表示してみる。

ライフサイクル

・DOMが生成されてから破棄されるまでの一連の流れのこと
・各タイミングで実行させたい処理を「ライフサイクル関数」内に定義する。

 例1) Account画面表示する時に、Account一覧取得APIをコールして取得結果を画面に表示したい。
 例2) stateで管理しているsearchKeywordが更新される度に検索処理をかけ直す。

「クラスコンポーネント」のライフサイクル関数

今回は関数コンポーネントで実装しているが、勉強がてらクラスコンポーネントのライフサイクル関数についてもMEMOしておく。

componentDidMount()

・Component が Mount された後に実行される。
・Ajax でデータフェッチ(初回)
・DOM に対する処理を行う(初回)

componentDidUpdate()

・Component の props または state が変更されたときに実行される。
・Ajax でデータフェッチ(2回目以降)
・DOM に対する処理を行う(2回目以降)

componentWillUnmount()

・Component が Unmount されるときに実行される。
・componentDidMount() で行った処理の解除を行うことが多い。

「関数コンポーネント」のライフサイクル関数

・componentDidMount()
・componentDidUpdate()
・componentWillUnmount()
は、関数コンポーネントだとuseEffect()1つで済む。

useEffect()

構文

useEffect(() => {
  /* 第1引数には実行させたい副作用関数を記述*/
  console.log('副作用関数が実行されました!')
},[依存する変数の配列]) // 第2引数には副作用関数の実行タイミングを制御する依存データを記述

・第2引数を省略した場合、コンポーネントがレンダリングされるたびに、第1引数で渡した副作用関数が実行される=componentDidMount()扱い

useEffect()に渡す無名関数はasyncだと怒られるので、そうならないようにthen().catch()等で完結させる

Reactでデータ取得する方法についてまとまっているサイト

Account画面でデータ表示してみる。

今のAccount画面
image.png
今のsrc/routes/Account.tsx

export const Account = () => <h1>Account</h1>;

「Account」という文字だけ表示されている画面を、Account情報一覧が表示される感じにしたい。

やること
・画面表示時/componentDidMount()実行時 に、Account一覧取得APIをコールする。
・取得結果を画面に表示する。

APIサーバ構築するのはしんどいので、今回はaxiosでJSONファイルを返す。

yarn add axios

public/data/accounts.json を用意

[
  {
    "id": "act_0000001",
    "name": "Anthony",
    "age": 26,
    "gender": "男"
  },
  {
    "id": "act_0000002",
    "name": "Bryant",
    "age": 36,
    "gender": "男"
  },
  {
    "id": "act_0000003",
    "name": "Carmelo",
    "age": 35,
    "gender": "男"
  },
  {
    "id": "act_0000004",
    "name": "Daisy",
    "age": 21,
    "gender": "女"
  }
]

src/routes/Account.tsx を修正

// axiosをimport
import axios from "axios";
import { useEffect, useState } from "react";
import { Box, Table, Thead, Tbody, Tr, Th, Td } from "@chakra-ui/react";

// Account情報入れ物クラス
class AccountDto {
  constructor(
    public id = "",
    public name = "",
    public age = 0,
    public gender = ""
  ) {}
}

export const Account = () => {
  // アカウント情報格納用のstateを用意
  const [accounts, setAccounts] = useState([]);
  // useEffect()に渡す無名関数はasyncだと怒られるので、そうならないようにthen().catch()等で完結させる
  useEffect(() => {
    // publicフォルダ配下に対してHTTPリクエストを行うため「public/data/account.json」を取得
    axios.get("/data/accounts.json").then((res) => {
      setAccounts(res.data);
    });
  }, []);

  return (
    <div>
      <Box m="10px">アカウント管理画面</Box>
      <Table>
        <Thead>
          <Tr>
            <Th>ID</Th>
            <Th>NAME</Th>
            <Th>AGE</Th>
            <Th>GENDER</Th>
          </Tr>
        </Thead>
        <Tbody>
          {accounts.map((a: AccountDto) => {
            return (
              <Tr>
                <Td>{a.id}</Td>
                <Td>{a.name}</Td>
                <Td>{a.age}</Td>
                <Td>{a.gender}</Td>
              </Tr>
            );
          })}
        </Tbody>
      </Table>
    </div>
  );
};

画面こんな感じにできた。
image.png

Account情報テーブルをコンポーネント化する&props利用

やること
・Account.tsxの<Table>~~</Table>の部分をsrc/components/account/AccountTable.tsxとしてコンポーネント化する。
・親コンポーネント(Account.tsx)から子コンポーネント(AccountTable.tsx)へ値(Account一覧情報)をprops経由で渡す。

propsとは

・親コンポーネントから子コンポーネントへ値を渡すために使うパイプ的な役割なやつ

関数コンポーネントでのpropsの渡し方

渡す方(親コンポーネント)

Account.tsx

<AccountTable accounts={accounts} />

受け取る方(子コンポーネント)

AccountTable.tsx

class AccountDto {
  constructor(
    public id = "",
    public name = "",
    public age = 0,
    public gender = ""
  ) {}
}

// propsとして受け取る型を定義
type Props = {
  accounts: AccountDto[];
};

// 関数の引数経由でpropsを受け取る
export const AccountTable = (props: Props) => {
  return (
    <Table>
      <Thead>
        <Tr>
          <Th>ID</Th>
          <Th>NAME</Th>
          <Th>AGE</Th>
          <Th>GENDER</Th>
        </Tr>
      </Thead>
      <Tbody>
        {props.accounts.map((a: AccountDto) => {
          return (

コンポーネント化&propsでアカウント情報一覧を渡してみた。

親:src/routes/Account.tsx

import axios from "axios";
import { useEffect, useState } from "react";
import { AccountTable } from "../components/account/AccountTable";
import { Box } from "@chakra-ui/react";

export const Account = () => {
  const [accounts, setAccounts] = useState([]);

  useEffect(() => {
    axios.get("/data/accounts.json").then((res) => {
      setAccounts(res.data);
    });
  }, []);

  return (
    <div>
      <Box m="10px">アカウント管理画面</Box>
      <AccountTable accounts={accounts} />
    </div>
  );
};

子:src/components/AccountTable.tsx

import { Table, Thead, Tbody, Tr, Th, Td } from "@chakra-ui/react";

class AccountDto {
  constructor(
    public id = "",
    public name = "",
    public age = 0,
    public gender = ""
  ) {}
}

// propsとして受け取る型を定義
type Props = {
  accounts: AccountDto[];
};

export const AccountTable = (props: Props) => {
  return (
    <Table>
      <Thead>
        <Tr>
          <Th>ID</Th>
          <Th>NAME</Th>
          <Th>AGE</Th>
          <Th>GENDER</Th>
        </Tr>
      </Thead>
      <Tbody>
        {props.accounts.map((a: AccountDto) => {
          return (
            <Tr>
              <Td>{a.id}</Td>
              <Td>{a.name}</Td>
              <Td>{a.age}</Td>
              <Td>{a.gender}</Td>
            </Tr>
          );
        })}
      </Tbody>
    </Table>
  );
};

アカウント詳細画面を作る

アカウント一覧テーブルの「詳細」ボタンを押すと、詳細画面が開かれるようにする。
image.png

dynamic routingの設定

詳細画面を開くときに、パラメータとしてアカウントIDを渡して、そのIDでアカウント情報取得APIをたたく&詳細画面に結果を表示する。

ルーティング設定追加

<Route path="/account/:id" element={<AccountDetail />} />を追加

export const App = () => {
  return (
    <ChakraProvider theme={theme}>
      <Flex w="100vw" h="100wh">
        <TopHeader />
        <Box mt="100px">
          <Flex>
            <BrowserRouter>
              <SideMenu />
              <Box w="70vw">
                <Routes>
                  <Route path="/" element={<Dashboard />} />
                  <Route path="/account/:id" element={<AccountDetail />} />
                  <Route path="/account" element={<Account />} />
                  <Route path="/charts" element={<Charts />} />
                  <Route path="/dashboard" element={<Dashboard />} />
                  <Route path="/mailBox" element={<MailBox />} />
                  <Route path="/message" element={<Message />} />
                  <Route path="/rateReview" element={<RateReview />} />
                  <Route path="/weather" element={<Weather />} />
                </Routes>
              </Box>
            </BrowserRouter>
          </Flex>
        </Box>
      </Flex>
    </ChakraProvider>
  );
};

アカウント詳細画面の作成

・パラメータに渡したIDをuseParams関数で取得する。 ※これもreact-router-dom v6のもの

import axios from "axios";
import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import { Box } from "@chakra-ui/react";

class AccountDto {
  constructor(
    public id = "",
    public name = "",
    public age = 0,
    public gender = ""
  ) {}
}

export const AccountDetail = () => {
  const [account, setAccount] = useState(new AccountDto());
  // パラメータ取得
  const params = useParams();
  useEffect(() => {
    // IDをキーにアカウント情報取得
    axios.get(`/data/account_${params.id}.json`).then((res) => {
      setAccount(res.data);
    });
  /// useEffect関数の第2引数に空配列を指定=無限ループ防止
  }, []);

  return (
    <Box m="20px">
      <h1>ID{account.id}</h1>
      <h1>NAME{account.name}</h1>
      <h1>AGE{account.age}</h1>
      <h1>GENDER{account.gender}</h1>
    </Box>
  );
};

アカウント情報テーブルの「詳細」ボタンをクリック→詳細画面に移動するようにする

navigate("/account/${a.id}")で詳細画面に移動

AccountTable.tsx

      <Tbody>
        {props.accounts.map((a: AccountDto) => {
          return (
            <Tr>
              <Td>{a.id}</Td>
              <Td>{a.name}</Td>
              <Td>{a.age}</Td>
              <Td>{a.gender}</Td>
              <Td>
                <Button
                  colorScheme="gray"
                  variant="ghost"
                  onClick={() => navigate(`/account/${a.id}`)}
                >
                  <Text m="10px">詳細</Text>
                </Button>
              </Td>
            </Tr>
          );
        })}
      </Tbody>

動作確認

・ID「act_0000001」をパラメータに渡す
image.png
・ID「act_0000002」をパラメータに渡す
image.png

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?