メンバー・勤怠・タスクをひとつの画面へ。React初心者がMembersページで学んだこと
前回の記事では、Team VisualizerのTasksページについて紹介しました。
今回は、チームに所属するメンバーを確認・管理するMembersページについて書いていきます。
Membersページでは、メンバーの追加・削除・検索だけでなく、勤怠状況や担当タスクも確認できます。
制作を通して学んだuseState・useEffect・useMemo・React Routerの使い方も、初心者なりの言葉で紹介します。

チーム全体の状況を4つのカードで表示
ページ上部には、次の情報をカード形式で表示しています。
登録メンバー数
本日の出勤人数
進行中のタスク数
部署数
ダッシュボードと同じように、チームの状況を短時間で確認できるようにするためです。
出勤人数や進行中のタスク数は、useMemoを使って計算しています。
const workingMemberCount = useMemo(() => {
return membersWithAttendance.filter(
(member) => member.attendance === "出勤"
).length;
}, [membersWithAttendance]);
const totalActiveTasks = useMemo(() => {
return tasks.filter(
(task) => task.status === "進行中"
).length;
}, [tasks]);
useMemoは、指定したデータが変わったときだけ計算をやり直すReact Hooksです。
今回は、勤怠情報が変わったときに出勤人数を、タスク情報が変わったときに進行中のタスク数を計算しています。
新しいメンバーを追加する
「新規メンバー」ボタンを押すと、名前・役割・部署・役職を入力する画面が開きます。

入力内容はuseStateで管理しています。
const [newMember, setNewMember] = useState({
name: "",
role: "メンバー",
department: "",
position: "",
});
useStateは、画面上で変化するデータを管理するReact Hooksです。
保存すると、入力したメンバーを一覧の先頭に追加します。
setMemberList((previousMembers) => [
member,
...previousMembers,
]);
setMemberListによってデータが変わると、Reactが画面を再表示するため、新しいメンバーがすぐに一覧へ反映されます。

また、名前・部署・役職が入力されていない場合や、同じ名前がすでに登録されている場合は、追加できないようにしています。
担当タスクがあるメンバーは削除できない
各メンバーカードの削除ボタンから、登録したメンバーを削除できます。
削除にはfilter()を使用しています。
setMemberList((previousMembers) =>
previousMembers.filter(
(member) => member.id !== deletingMember.id
)
);
ただし、担当タスクが残っているメンバーを削除すると、担当者のいないタスクが発生してしまいます。
そこで、削除するメンバーが担当しているタスクを確認しています。
const deletingMemberTasks = useMemo(() => {
if (!deletingMember) return [];
return tasks.filter(
(task) =>
task.assignee === deletingMember.name
);
}, [deletingMember, tasks]);
担当タスクが1件以上ある場合は削除ボタンを無効にし、先に担当者を変更するように案内します。
今回のMembersページで、特に意識した部分です。
検索と絞り込みでメンバーを探す
メンバーが増えても目的の人を見つけられるように、次の検索・絞り込み機能も実装しました。
名前・部署・役職から検索
部署で絞り込み
リーダー・メンバーで絞り込み
出勤・未出勤などの勤怠で絞り込み
絞り込み後のメンバーは、useMemoとfilter()で作っています。
const filteredMembers = useMemo(() => {
return membersWithAttendance.filter(
(member) => {
// 検索条件に一致するか確認
return (
matchesKeyword &&
matchesDepartment &&
matchesRole &&
matchesAttendance
);
}
);
}, [
membersWithAttendance,
searchKeyword,
departmentFilter,
roleFilter,
attendanceFilter,
]);
検索条件が変わると、条件に一致したメンバーだけが表示されます。
useEffectでほかのページとデータをつなぐ
Membersページでは、メンバー情報だけでなく、Tasksページのタスクと本日の勤怠記録も読み込んでいます。
useEffectは、ページを表示したときや、指定したデータが変わったときに処理を実行するReact Hooksです。
useEffect(() => {
localStorage.setItem(
"members",
JSON.stringify(memberList)
);
}, [memberList]);
メンバーを追加・削除してmemberListが変わると、最新の情報をlocalStorageへ保存します。
また、タスクや勤怠の更新を検知し、Membersページにも最新の情報を反映しています。
この仕組みによって、メンバー・タスク・勤怠が別々の情報ではなく、つながったデータとして表示されます。
React Routerで詳細ページへ移動する
各カードの「メンバー詳細」を押すと、そのメンバー専用の詳細ページへ移動します。
<Link to={`/members/${member.id}`}>
メンバー詳細
</Link>
例えば、IDがaのメンバーなら、移動先は/members/aになります。
React Routerを使うことで、ページ全体を読み込み直さずに画面を切り替えられます。
メンバーごとに異なるIDをURLへ含めることで、同じ詳細ページの仕組みを複数のメンバーに使えるようにしています。

Membersページは情報をつなぐ画面
今回は、Team VisualizerのMembersページについて紹介しました。
このページで意識したのは、次の点です。
チーム全体の状況を4つのカードで確認する
メンバーを追加・削除する
検索や絞り込みから目的のメンバーを探す
担当タスクがあるメンバーの誤削除を防ぐ
メンバーの詳細ページへ移動する
タスクや勤怠の情報をメンバーとつなげる
制作を通して、useState・useEffect・useMemo・React Routerを、実際のアプリでどのように使うのか学ぶことができました。
まだlocalStorageを使った学習段階ですが、今後はFirebaseへ移行し、複数人で情報を共有できるようにしていく予定です。
少しずつでも機能を追加していくことで、React初心者でもオリジナルアプリを形にできると感じています。
最後まで読んでいただき、ありがとうございました。
