【React-TS + MUI】③メンバーリストのWEBアプリを作成してみた

★★★ イベント情報 ★★★
◇【参加登録受付中】Kong Summit, Japan 2022◇
今年は12月15日に開催決定!最新情報とデモとともにKongと事例/ユースケースのご紹介などAPIエコノミーやマイクロサービスに関心のある開発者の方にとっては必見です。ぜひお申し込みください!イベントの詳細・お申込はこちら

★★★ Live配信告知 ★★★
◇11月29日開催 19:00~ 世界一わかりみの深いクラウドネイティブon Azure◇
テーマは「Web App for ContainersとKeycloakで最速OpenID Connect」です!

◇11月30日開催 17:00〜 知ってると ちょっと便利なコマンド集◇
知っていると少し効率の上がるようなコマンドをいくつかご紹介します!

こんにちは、2022年4月入社の庄野です。今回は、新卒1年目の私がReact-TypeScript + Material-UI (以下、React,TS,MUI)の技術を使った、簡単なWEBアプリの作り方を3つの記事にわたって1から紹介したいと思います。

この記事はリスト表示編です。

  1. 導入編
  2. カスタムフック編
  3. リスト表示編

対象

  • React、TS初心者
  • APIを扱ってみたい人
  • カスタムフックを作成したい人
  • MUIを使ってみたい人

やること

  • プロジェクトの作成
  • API用のモックサーバーを立てる
  • APIを取得するカスタムフック作成
  • MUIを使ってユーザーをリスト表示する

使用環境
開発環境は以下の通りです。

$ node --version
v16.17.1
$ npm --version
8.15.0
"@emotion/react": "^11.10.4",
"@emotion/styled": "^11.10.4",
"@mui/icons-material": "^5.10.6",
"@mui/lab": "^5.0.0-alpha.102",
"@mui/material": "^5.10.7",
"@stoplight/prism-cli": "^4.10.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"typescript": "^4.8.4",

前回

前回の記事では、モックサーバーを立てて、API取得するカスタムフックを作成しデータを他のコンポーネントでも扱えるようにしました。

今回

今回は、いよいよ取得したデータをMUIのコンポーネントを使ってリスト表示していきたいと思います。

リスト表示

それでは、各コンポーネントの作成に移ります。リスト表示するコンポーネントは以下のように、UserListの中にUserCard、さらにその中にUserIconのコンポーネントが含まれる構造となっており、UserListをUserCard、UserIconへと細分化して開発していきます。

アイコン

アイコンのコンポーネントでは、ユーザー(前回の記事でusertype.tsにおいて{name, status, thumbnail, useID}の要素で定義)のpropsを受け取ってから、アイコン表示と、勤務状態に応じたステータスを表示します。完成図は以下のようになります。勤務状態によって、周りの色が変わります。(以下はステータスがworkingの場合)

特にこだわりなければ、勤務状態に応じたステータス表示はAvatar – Material UI – MUIのWith Badge(以下)を参考にしてよいと思います。私は、ステータスをアイコン周りの色で表現したかったので、Paperコンポーネントの上にAvatarコンポーネントを載せて実装しました。

ソースは以下。

import { memo, FC } from "react";

import Avatar from "@mui/material/Avatar";
import { Paper } from "@mui/material";

import { User } from "../types/usertype";

type Props = {
  user: User; // ユーザー情報{name, status, thumbnail, useID}
  size?: number; // アイコンの大きさ
};

export const UserIcon: FC<Props> = memo((props) => {
  const { user, size = 50 } = props;

  return (
    <>
      <Paper // アイコン周り外枠
        sx={{
          padding: "6px",
          margin: 1,
          borderRadius: "100%",
          bgcolor: "#757575",
          ...(user.status === "working" && { // 勤務中の場合
            bgcolor: "#70c4bc",
          }),
          ...(user.status === "notWorking" && { // 退勤中の場合
            bgcolor: "#ea8f8f",
          }),
          ...(user.status === undefined && { // 不明の場合
            bgcolor: "background.default",
          }),
        }}
      >
        <Avatar // アイコン
          alt={user.name}
          src={user.thumbnail}
          sx={{ width: size, height: size, border: 1 }}
        />
      </Paper>
    </>
  );
});

以上のようにすると、アイコンを簡単かつ綺麗に表示できたと思います。sx propsでコンポーネントごとにcssをあてられるのもコードを簡潔にできる要因だと思います。ちなみに、アイコン周りの色を決めているbgcolorColor – Material UI – MUIから以下のように、実際に色味などを調整して選びました。

ユーザーカード

では、次にユーザーの情報を載せた以下のような”カード”を作ります。同じく、ユーザーのpropsを受け取り、先ほど作成したアイコンと、名前、勤務状態を表示します。

ソースは以下。

import { memo, FC } from "react";

import ListItemText from "@mui/material/ListItemText";
import ListItemIcon from "@mui/material/ListItemIcon";
import { MenuItem } from "@mui/material";

import { UserIcon } from "../atoms/UserIcon";
import { User } from "../types/usertype";

type Props = {
  user: User;
};

export const UserCard: FC<Props> = memo((props) => {
  const { user } = props; // ユーザー情報受け取り

  return (
    <>
      <MenuItem>
        <ListItemIcon>
          <UserIcon user={user} /> // アイコン
        </ListItemIcon>
        <ListItemText
          primary={user.name} // 名前
          primaryTypographyProps={{ fontSize: { xs: 20, md: 40 } }}
          secondary={ // 勤務状態
            user.status === "working"
              ? "勤務中"
              : user.status === "notWorking" && "退勤"
          }
        />
      </MenuItem>
    </>
  );
});

ListItemTextのpropsで、primarysecondaryに要素を渡すことによって特にデザインする必要なく、テキスト覧をいい感じに表示してくれます。React List component – Material UI – MUIのドキュメントで例(以下)がある通り、ListItemButtonListItemIconなど、リストに載せたいボタンや、アイコンなど該当するコンポーネントでラップすれば、ある程度決まったデザインで表示できます。

ユーザーリスト

それでは、ユーザー一人を表示できるようになったので、リスト表示していきたいと思います。
また、勤務状態でメンバーをフィルタリングできるようにします。

import { useEffect, useState } from "react";
import { memo, FC } from "react";

import Paper from "@mui/material/Paper";
import MenuList from "@mui/material/MenuList";
import { Box, Tab } from "@mui/material";
import TabContext from "@mui/lab/TabContext";
import TabList from "@mui/lab/TabList";
import TabPanel from "@mui/lab/TabPanel";

import { UserCard } from "../molecules/UserCard";
import { useAllUsers } from "../hooks/useAllUsers";

export const UserList: FC = memo(() => {
  const [value, setValue] = useState("1"); // タブ番号
  const { getAllUsers, users } = useAllUsers(); // カスタムフック

  const handleChange = (event: unknown, newValue: string) => { // タブ切り替え
    setValue(newValue);
  };

  useEffect(() => {
    getAllUsers(); // API取得
  }, []);

  return (
    <Paper
      sx={{
        width: `80%`,
        overflow: "auto",
        m: 1,
        borderRadius: 5,
        boxShadow: 10,
      }}
    >
      <Box sx={{ width: "100%", typography: "body1" }}>
        <TabContext value={value}>
          <Box sx={{ borderBottom: 1, borderColor: "divider" }}>
            <TabList
              onChange={handleChange} // 選択したタブに切り替える(valueを切り替え)
              aria-label="lab API tabs example"
              centered // 中央揃え
              variant="fullWidth" // 最大横幅
            >
             // タブ 
              <Tab label="メンバー一覧" value="1" />
              <Tab label="勤務中" value="2" />
              <Tab label="退勤" value="3" />
            </TabList>
          </Box>
           // 選択されたタブを表示(valueに応じて表示が変わる)
          <TabPanel value="1">
            <MenuList>
              {users.map((user) => (
                <UserCard user={user} key={user.userID} />
              ))}
            </MenuList>
          </TabPanel>
          <TabPanel value="2">
            <MenuList>
              {users.map(
                (user) =>
                  user.status === "working" && (
                    <UserCard user={user} key={user.userID} />
                  )
              )}
            </MenuList>
          </TabPanel>
          <TabPanel value="3">
            <MenuList>
              {users.map(
                (user) =>
                  user.status === "notWorking" && (
                    <UserCard user={user} key={user.userID} />
                  )
              )}
            </MenuList>
          </TabPanel>
        </TabContext>
      </Box>
    </Paper>
  );
});

まず、前の記事で実装したuseAllUsersのカスタムフックで表示するユーザーのデータを取得します。次にタブが選択されるたびに更新されるvalueをuseStateで定義し、そのvalueに応じて表示内容を変えています。あとは、mapメソッドで条件によって、表示するユーザーを変えれば完成です。

導入編の記事で、すでにMemberList.tsxMainコンポーネントに内包されているので、表示できるようになっていると思います。

結果

お疲れ様です。

以下の動画のようなものができたと思います。

さいごに

以上3つの記事で、カスタムフックを使ってユーザーのAPIを取得し、ユーザーをリスト表示するWEBアプリを作ってみました。
カスタムフックは、ビューとロジックを切り分けて書けるのが一番の魅力でした。また、MUIはドキュメントが優秀と感じました。使用例が充実しているため、コンポーネントの使い方を知るより、コピペで少し手直しするだけでもそれなりのUIができてしまいます。すでにあるものを再利用できるReactだからこそですね。

以上です。





ご覧いただきありがとうございます。
ブログの最新情報はSNSでも発信しております。
ぜひTwitterのフォロー&Facebookページにいいねをお願い致します!



>> 雑誌等の執筆依頼を受付しております。
   ご希望の方はお気軽にお問い合わせください!


ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。

Be the first to comment

Leave a Reply

Your email address will not be published.


*


質問はこちら 閉じる