理解を深めるためのメモ兼、思い出すため用です。
作成したもの
今回作成するオリジナルアプリの見た目の作成、ヘッダーのフィルターボタンの追加を行いました。

見た目の作成
App.jsx:ルートの設定
App.jsx
function App() {
return (
<Router>
<Box pb="60px">
{" "}
{/* 下のメニューが被らないように余白を作る */}
<Routes>
<Route path="/" element={<Home />} />
<Route path="/analysis" element={<Analysis />} />
<Route path="/calendar" element={<Calendar />} />
</Routes>
</Box>
<Navbar />
</Router>
);
}
Navbar.jsx:画面下のボタン(今は必要最低限、css部分はAI)

Navbar.jsx
const Navbar = () => {
return (
<Flex
as="nav"
fixed="bottom"
position="fixed"
bottom="0"
width="100%"
bg="white"
borderTop="1px solid #eee"
justify="space-around"
py="5"
>
<Link to="/">
<Text fontSize="ms">一覧</Text>
</Link>
<Link to="/analysis">
<Text fontSize="ms">分析</Text>
</Link>
<Link to="/calendar">
<Text fontSize="ms">カレンダー</Text>
</Link>
</Flex>
);
};
Home.jsx:ホーム画面全体(HeaderとCardCompを扱ってる)
→ここが今回の肝。フィルター機能。これについては後ほど記述。見た目はreturn以降の部分

Home.jsx
const Home = () => {
// ダミーデータ
const data = [
{ id: 1, name: "ワイヤレスイヤホン", price: "5,800", category: "Amazon", date: "2026/01/29" },
{ id: 2, name: "冬物ニット", price: "3,200", category: "SHEIN", date: "2026/01/28" },
{ id: 3, name: "スマホケース", price: "1,500", category: "Amazon", date: "2026/01/27" },
];
// 「現在選択中のカテゴリ」を管理するState(初期値は "全て")
const [selectedCategory, setSelectedCategory] = useState("全て");
// カテゴリだけを取ってきて配列で管理
const categories = ["全て", ...new Set(data.map((item) => item.category))];
// 表示するデータを選定するところ
// 選択中のカテゴリが「全て」ならdataを、それ以外ならdataの中のカテゴリと一致するものだけ取り出す
const filteredData =
selectedCategory === "全て"
? data
: data.filter((item) => item.category === selectedCategory);
return (
<Box minH="100vh" bg="gray.50">
{/* Headerに、現在の選択状態と、カテゴリ配列、「今、どのカテゴリが選ばれているか」を書き換えるための専用リモコンを渡す */}
<Header
categories={categories}
selectedCategory={selectedCategory}
setSelectedCategory={setSelectedCategory}
/>
<Box p={4} pb="100px">
{/* 選定されたデータの中身を1つずつ取り出してCardCompに渡す */}
{filteredData.map((item) => (
<CardComp
key={item.id}
name={item.name}
price={item.price}
category={item.category}
date={item.date}
/>
))}
</Box>
{/*「+」ボタン */}
<IconButton
icon={<AddIcon />}
colorScheme="orange"
isRound
size="lg"
position="fixed"
bottom="100px"
right="20px"
shadow="2xl"
onClick={() => alert("追加機能はこれから実装!")}
/>
</Box>
);
};
Header.jsx
const Header = ({ categories, selectedCategory, setSelectedCategory }) => {
return (
<VStack
p={4}
borderBottom="1px solid #eee"
spacing={3}
bg="white"
position="sticky"
top="0"
zIndex="10"
>
<Text fontSize="xl" fontWeight="bold">
Recap
</Text>
<HStack spacing={2} overflowX="auto" width="100%" py={1}>
{/* 受け取ったカテゴリ一覧から1つずつ取り出す */}
{categories.map((cat) => (
<Button
key={cat}
size="sm"
borderRadius="full"
// 選ばれているカテゴリなら色を塗りつぶし(solid)、そうでなければ枠線(outline)
variant={selectedCategory === cat ? "solid" : "outline"}
colorScheme="orange"
// クリックされたら、HomeのselectedCategoryを更新する
onClick={() => setSelectedCategory(cat)}
>
{cat}
</Button>
))}
</HStack>
</VStack>
);
};
CardComp.jsx
const CardComp = ({ name, price, category, date }) => {
return (
<Box p={4}>
<Box bg="orange.100" p={5} borderRadius="lg" shadow="md" mt={4}>
<Flex align="center">
<VStack align="start" spacing={0}>
<Text fontWeight="bold">{name}</Text>
<Text fontSize="sm" color="gray.600">
{category}
</Text>
</VStack>
<Spacer />
<VStack align="end" spacing={0}>
<Text fontWeight="bold">¥{price}</Text>
<Text fontSize="xs">{date}</Text>
</VStack>
</Flex>
</Box>
</Box>
);
};
フィルタリング機能
やりたいこと
1.カテゴリごとにヘッダーにボタンを作成
Home.jsx
// カテゴリだけを取ってきて配列で管理
const categories = ["全て", ...new Set(data.map((item) => item.category))];
Setは、重複する値は格納しない。
これを活用して、ダミーデータdataをマップしてカテゴリを1つずつみていけば、重複せずにカテゴリを全て取り出すことができる。
あとは、このカテゴリの配列をHeaderコンポーネントに渡してあげれば良い。
Header.jsx
<HStack spacing={2} overflowX="auto" width="100%" py={1}>
{/* 受け取ったカテゴリ一覧から1つずつ取り出す */}
{categories.map((cat) => (
<Button>{cat}</Button>
))}
</HStack>
受け取ったカテゴリ一覧をmapで1つずつみて、Buttonをそれぞれ生成すればOK。
2.ボタンを押したら、そのカテゴリの履歴だけを表示する(フィルタリング)
Home.jsx
// 「現在選択中のカテゴリ」を管理するState(初期値は "全て")
const [selectedCategory, setSelectedCategory] = useState("全て");
// 表示するデータを選定するところ
const filteredData =
selectedCategory === "全て"
? data
: data.filter((item) => item.category === selectedCategory);
- まずは、Home.jsxに選択されているカテゴリを管理するStateを用意
-
filteredData:選択中のカテゴリが「全て」ならdataを、それ以外ならdataの中のカテゴリと一致するものだけ取り出す。(selectedCategoryがAmazonなら、データの中のcategoryがAmazonのものだけ取り出す。)
Home.jsx
{filteredData.map((item) => (
<CardComp
key={item.id}
name={item.name}
price={item.price}
category={item.category}
date={item.date}
/>
))}
そして、CardCompにはfilteredDataでフィルタリングしたデータを渡す。すると自動でフィルタリングされる!
Header.jsx
<HStack spacing={2} overflowX="auto" width="100%" py={1}>
{/* 受け取ったカテゴリ一覧から1つずつ取り出す */}
{categories.map((cat) => (
<Button
key={cat}
size="sm"
borderRadius="full"
// 選ばれているカテゴリなら色を塗りつぶし(solid)、そうでなければ枠線(outline)
variant={selectedCategory === cat ? "solid" : "outline"}
colorScheme="orange"
// クリックされたら、HomeのselectedCategoryを更新する
onClick={() => setSelectedCategory(cat)}
>
{cat}
</Button>
))}
</HStack>
そして、
-
variant={selectedCategory === cat ? "solid" : "outline"}で選択されているボタンの見た目を変える。 -
onClick={() => setSelectedCategory(cat)}でクリックされたら選択中Stateを変更する。
以上です!ご覧頂きありがとうございました!


