ミライトデザイン Advent Calendar 2024 16日目の記事になります。
15日目は takuma さんの 「DynamoDB 全くわからないのでまとめてみた」の記事でした。
私も DynamoDB 全くわからない勢ですが、
RDBと比べて設計の考え方が全然違うんだなと感じました。
とても参考になりました!
はじめに
現在、私は React を使用したプロジェクトに携わっています。
2024年も残りわずかとなり、今年お世話になったライブラリを振り返ってみることにしました。
目的
プロジェクトでは、自分以外のメンバーが導入したライブラリも多くあります。
そのため、これらのライブラリについて調べ、実際に試してみて、使い方をざっくり理解したいと考えています。
今回は、その中で紹介しやすかったり、便利だと思った5つのライブラリを紹介します。
ライブラリ紹介について
以下の構成で説明を進めます。
- 実現したいこと
- ライブラリ名
- ライブラリ概要
実現したいこと: UI コンポーネントを効率的に構築したい
ライブラリ名: Chakra UI
ライブラリ概要
Chakra UIとは、React ベースの UI コンポーネントライブラリの一つで、
開発者が簡単かつ効率的にモダンな UI を構築できるよう設計されています。
特に、スタイルとテーマのカスタマイズが容易なため、デザインの一貫性を保ちながら柔軟な対応が可能です。
例として以下のようなデザインを作成してみます。
実装例
import { Box, Image, Text, Button, HStack, VStack } from "@chakra-ui/react";
import { FaCat } from "react-icons/fa6";
// ______________________________________________________
//
const Component = () => {
return (
<Box
maxW="sm"
borderWidth="1px"
borderRadius="lg"
overflow="hidden"
p={6}
bg="white"
boxShadow="md"
>
<Image src="./images/cat1.jpeg" alt="Sample Image" />
<Box mt={4} textAlign="center">
<Text fontWeight="bold" fontSize="xl">
サンプルカード
</Text>
<Text mt={2} color="gray.600">
Chakra UI を使って簡単なレイアウトを作成してみる。
</Text>
<HStack spacing={8} justifyContent="center" p={4} mt={4}>
<VStack spacing={2} align="center">
<Text fontWeight="bold" fontSize="md" color="teal.500">
サンプル1
</Text>
<Text fontSize="sm" color="gray.600">
説明テキスト1
</Text>
</VStack>
<VStack spacing={2} align="center">
<Text fontWeight="bold" fontSize="md" color="teal.500">
サンプル2
</Text>
<Text fontSize="sm" color="gray.600">
説明テキスト2
</Text>
</VStack>
</HStack>
<Button colorScheme="teal" mt={6} leftIcon={<FaCat />}>
ボタン
</Button>
</Box>
</Box>
);
};
いくつか特徴を挙げます
- 豊富なコンポーネント
- ボタン、入力フィールド、モーダル、カードなど、日常的によく使用される基本コンポーネントが多数用意されています
- レイアウトの容易さ
- クラス名を考える必要がなく、レイアウト用のコンポーネント(例:
HStack
,VStack
)を使えば簡単に配置ができます
- クラス名を考える必要がなく、レイアウト用のコンポーネント(例:
- スタイルのショートハンド
-
p={6}
,mt={4}
などの簡潔なスタイル指定が可能です
-
- カスタムテーマ機能
- デフォルトのテーマをベースに、独自の色やフォントを簡単に設定できます
- ブランドカラーやフォントサイズなどを指定したり、コンポーネントのスタイルを上書きすることが可能です
- 参考記事はこちら
※React の UI コンポーネントライブラリは、Chakra UI の他にも Material-UI, React Bootstrap など多く存在しますが、今回は Chakra UI に限定して紹介しました。
実現したいこと: 棒(円)グラフを描きたい
ライブラリ名: recharts
ライブラリ概要
データの視覚化に便利なライブラリです。
例えば、以下のような「男女の年代比率」や「家計簿管理での収支のカテゴリ比率」を簡単に表示できます。
実装例:年代比率の棒グラフ
import { Box, Heading } from "@chakra-ui/react";
import {
ResponsiveContainer,
BarChart,
CartesianGrid,
XAxis,
YAxis,
Bar,
} from "recharts";
// ______________________________________________________
//
const data = [
{ name: "〜20代", value: 10 },
{ name: "30代", value: 40 },
{ name: "40代", value: 30 },
{ name: "50代〜", value: 5 },
];
const Component = () => {
return (
<Box p={4} boxShadow="md" mt={6}>
<Heading as={"h3"} className="chart-heading" fontSize={"lg"} mb={3}>
年代比率
</Heading>
<ResponsiveContainer width="100%" height={200}>
{/* 棒グラフを表示するコンポーネント */}
<BarChart data={data}>
{/* グラフ背景の線を表示するグリッド */}
<CartesianGrid strokeDasharray="3 3" />
<XAxis tickLine={false} dataKey="name" />
<YAxis
tickLine={false}
type="number"
tickFormatter={(value) => `${value}%`}
/>
{/* 実際のデータを棒グラフとして描画 */}
<Bar dataKey="value" fill="#DF6160" barSize={30} />
</BarChart>
</ResponsiveContainer>
</Box>
);
};
必要なデータがあれば、棒グラフ (BarChart) を簡単に作成できます。
また、棒グラフだけでなく、円グラフなら PieChart
コンポーネントを使用できます。
実現したいこと: 画像一覧から写真を選択・拡大表示し、次の写真に移動させたい
ライブラリ名: yet-another-react-lightbox
ライブラリ概要
写真の拡大表示に加え、次の写真への移動が必要なため適したライブラリを検討しました。
候補はlightbox-react
とyet-another-react-lightbox
の2つでしたが、ダウンロード数と更新頻度の比較から後者を選択しました。
機能説明
- 画像をクリックすると、モーダルとして拡大表示されます
- モーダル内では矢印ボタンで次の画像に移動可能
- 閉じるボタンで元の画面に戻ります
※公式サンプルでは、ボタンでモーダルを開く例の記述がありましたが、
この記事では画像クリックでモーダルを開くように実装しています。
実装例
import { useState } from "react";
import Lightbox from "yet-another-react-lightbox";
import "yet-another-react-lightbox/styles.css";
import { SimpleGrid, Box, Image } from "@chakra-ui/react";
// ______________________________________________________
//
// 表示する画像の配列
const images = [
"cat1.jpeg",
"cat2.jpeg",
"cat3.jpeg",
"cat4.jpeg",
"cat5.jpeg",
"cat6.jpeg",
];
const Component = () => {
const [isOpen, setIsOpen] = useState(false); // Lightboxの表示状態
const [currentIndex, setCurrentIndex] = useState(0); // 現在表示している画像のインデックス
// 画像クリック時の処理
const handleClick = (index) => {
setCurrentIndex(index);
setIsOpen(true);
};
return (
<Box p={4} mt={50} mb={150}>
{/* 画像一覧のグリッド表示 */}
<SimpleGrid columns={2} spacing={4}>
{images.map((src, index) => (
<Image
key={index}
src={`./images/${src}`}
alt={`image-${index}`}
cursor="pointer"
onClick={() => handleClick(index)}
borderRadius="md"
boxShadow="md"
/>
))}
</SimpleGrid>
{/* Lightbox モーダル */}
<Lightbox
open={isOpen} // モーダルの開閉状態
index={currentIndex} // 現在表示している画像インデックス
close={() => setIsOpen(false)}
slides={images.map((image) => ({
src: `./images/${image}`,
alt: "image",
}))}
/>
</Box>
);
};
実現したいこと: 画面のスクロールに応じた要素の表示制御
ライブラリ名: react-intersection-observer
ライブラリ概要
フォーム登録ページでは、「登録ボタン」を固定フッターとして画面下部に表示していました。
しかし、ページの最下部までスクロールすると、最下部の要素が登録ボタンに隠れてしまう問題が発生。
そこで、画面のスクロール位置に応じて、最下部の登録ボタンが表示されたタイミングで固定フッターの登録ボタンを非表示にするよう調整しました。
機能説明
- 最初は固定フッターの「登録ボタン1」が表示されています
- 画面下部の「登録ボタン2」が表示されたタイミングで固定フッター(登録ボタン1)が非表示になり、下部の要素が隠れないようになります
実際例:コード
import styled from "styled-components";
import { useInView } from "react-intersection-observer";
// ______________________________________________________
//
const Component = ({ className }) => {
// ref: 監視対象の要素参照
// inView: 監視対象が画面内に入っているかどうかの判定フラグ
const [ref, inView] = useInView({
threshold: 0.1, // 要素の10%以上が表示されたときに検知
});
return (
<div className={className}>
<div className="content">
<div className="section">セクション 1</div>
<div className="section">セクション 2</div>
<div className="section">セクション 3</div>
<div className="section">セクション 4</div>
{/* 監視されているボタン */}
{/* refを与えた要素がウインドウ内に現れるとinViewがtrueになる */}
{!inView && <div className="fixed-button">登録ボタン1</div>}
{/* 監視対象のボタン */}
<button ref={ref} className="button">
登録ボタン2
</button>
<div className="section">フッター</div>
</div>
</div>
);
};
// ______________________________________________________
//
const StyledComponent = styled(Component)`
.content {
padding: 20px;
}
.section {
padding: 80px;
background: #f0f0f0;
margin: 20px 0;
}
.fixed-button {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
padding: 10px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
z-index: 100; /* フッターより前に表示させる */
width: 300px;
text-align: center;
}
.footer {
display: none;
padding: 20px;
background: #333;
color: white;
text-align: center;
margin-top: 20px;
}
.button {
padding: 10px 20px;
background: green;
border: none;
border-radius: 5px;
cursor: pointer;
width: 100%;
color: white;
font-size: 16px;
}
`;
実現したいこと: 画像をカルーセル表示したい
ライブラリ名: embla-carousel-react
ライブラリ概要
画像をカルーセル形式で表示するために使用したライブラリです。
カルーセルは、限られたスペースで多くの画像を見せたい場合などに有効ですね。
ユーザーはボタンや画像のサムネイルをクリックすることで、
スライドを切り替えることができます。
また、画像の枚数を(2/10など)表示したり、自動で画像が切り替わるような設定も可能です。
実際のコード例(スタイルは省略)
import styled from "styled-components";
import useEmblaCarousel from "embla-carousel-react";
import { useCallback } from "react";
// ______________________________________________________
//
// 表示する画像リスト
const images = [
"cat1.jpeg",
"cat2.jpeg",
"cat3.jpeg",
"cat4.jpeg",
"cat5.jpeg",
"cat6.jpeg",
];
const Component = ({ className }) => {
// emblaRef: スライダーの DOM 要素に関連付ける参照 (ref)。
// emblaApi: スライダー操作用の API オブジェクト。スライドの移動、状態管理に使用する
const [emblaRef, emblaApi] = useEmblaCarousel({ loop: true }); // スライダーの無限ループを有効にする
// 前のスライドへ移動
const onPrevButtonClick = useCallback(() => {
if (!emblaApi) return;
emblaApi.scrollPrev();
}, [emblaApi]);
// 次のスライドへ移動
const onNextButtonClick = useCallback(() => {
if (!emblaApi) return;
emblaApi.scrollNext();
}, [emblaApi]);
return (
<div className={className}>
<div className="slider">Slider</div>
{/* スライダー本体 */}
<div className="embla" ref={emblaRef} style={{ overflow: "hidden" }}>
<div className="embla__container" style={{ display: "flex" }}>
{images.map((src, index) => (
<div
className="embla__slide"
key={index}
style={{ flex: "0 0 100%" }}
>
<img
src={`./images/${src}`}
alt={`Slide ${index + 1}`}
style={{ width: "100%", height: "auto" }}
/>
</div>
))}
</div>
</div>
{/* スライド操作ボタン */}
<div className="embla__controls">
<div className="embla__buttons">
<button onClick={onPrevButtonClick}>Prev</button>
<button onClick={onNextButtonClick}>Next</button>
</div>
</div>
</div>
);
};
// ______________________________________________________
//
const StyledComponent = styled(Component)`
.slider {
font-size: 32px;
padding: 10px;
text-align: center;
}
.embla {
overflow: hidden;
}
.embla__container {
display: flex;
}
.embla__slide {
flex: 0 0 100%;
min-width: 0;
}
.embla__buttons {
width: 100%;
margin: 0 auto;
display: flex;
gap: 20px;
justify-content: center;
}
button {
background-color: #fff;
// border: 1px solid #000;
// background-color: #bce2e8;
border: none;
padding: 10px;
width: 100px;
font-weight: bold;
font-size: 24px;
}
`;
さいごに
この記事では5つの React ライブラリを紹介しました。
本当はもっと多くのライブラリを紹介する予定だったのですが、
調べたり整理するのに予想以上に時間がかかってしまい、紹介しきれませんでした。
また機会があれば、別の記事で他のライブラリも紹介したいと思います。
この記事がきっかけで、新たに使い始めるライブラリが見つかれば嬉しいです!
明日は、yuki さんの記事です。
よろしくお願いします!
参考