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

◆ Live配信スケジュール ◆
サイオステクノロジーでは、Microsoft MVPの武井による「わかりみの深いシリーズ」など、定期的なLive配信を行っています。
⇒ 詳細スケジュールはこちらから
⇒ 見逃してしまった方はYoutubeチャンネルをご覧ください
【5/21開催】Azure OpenAI ServiceによるRAG実装ガイドを公開しました
生成AIを活用したユースケースで最も一番熱いと言われているRAGの実装ガイドを公開しました。そのガイドの紹介をおこなうイベントです!!
https://tech-lab.connpass.com/event/315703/

こんにちは、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だからこそですね。

以上です。

アバター画像
About shou 6 Articles
2022年サイオステクノロジー入社、プロフェッショナルサービスライン所属。現在はDataStax Cassandraの導入支援として、開発や運用をしています。これに限らず、様々な分野の技術を吸収して発信できるようなエンジニア目指します。
ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

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

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


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



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

Be the first to comment

Leave a Reply

Your email address will not be published.


*


質問はこちら 閉じる