【React】useState(デモコンポーネント:続きを読むボタン)
Stateの概念とは
それぞれのコンポーネントが持っている状態です。
例
- エラーがあるのか、ないのか
- モーダルが開いているのか、いないのか
- ユーザーが入力した内容
useStateの使い方
1)「useState」をインポート
「React」からフック「useState」をインポートします
import { useState } from "react";
→関数「useState();」が使えるようになります
2)useStateの定義
配列の分割代入でうけとります
const [num, setNum] = useState();
// 配列の分割代入なので変数は任意の名前でOK
▼初期値の設定もできます
const [num, setNum] = useState(0);
3)ステートの中身を更新する
2)で定義した変数を使います
setNum(1);
実装例
続きを読むボタン
page.tsx
import React from "react";
import ReadMore from "@/components/readMore";
export default function Page() {
return (
<>
<ReadMore>
<p>続きを読むボタンの例</p>
<br />
<p>テキストテキストテキストテキストテキストテキストテキストテキストテキスト</p>
<p>テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト</p>
<p>テキストテキストテキスト</p>
<p>テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト</p>
<p>テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト</p>
<p>テキストテキストテキスト</p>
<p>テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト</p>
<p>テキストテキストテキスト</p>
<p>テキストテキストテキストテキストテキストテキストテキストテキストテキスト</p>
<p>テキストテキストテキスト</p>
</ReadMore>
</>
);
}
readMore.tsx
'use client';
import React, { useEffect, useRef, useState } from 'react';
import styles from '@/styles/readMore.module.css';
interface ReadMoreProps {
children: React.ReactNode;
}
const ReadMore: React.FC<ReadMoreProps> = ({ children }) => {
const [isExpanded, setIsExpanded] = useState(false);
const contentRef = useRef<HTMLDivElement>(null);
const [maxHeight, setMaxHeight] = useState<number | null>(null);
useEffect(() => {
if (contentRef.current) {
setMaxHeight(contentRef.current.scrollHeight); //scrollHeight: 要素のスクロールビューの高さを取得
}
}, [children]);
const toggleReadMore = () => {
setIsExpanded(!isExpanded);
};
return (
<div className={styles.readMoreWrapper}>
<div
className={`${styles.content} ${isExpanded ? styles.expanded : ''}`}
style={maxHeight ? { '--max-height': `${maxHeight}px`} as React.CSSProperties : {}}
>
<div
ref={contentRef}
className={`${styles['grad-item']} ${isExpanded ? styles['no-gradient'] : ''}`}>
{children}
</div>
</div>
<button className={styles.readMoreButton} onClick={toggleReadMore}>
{isExpanded ? '閉じる' : '続きを読む'}
</button>
</div>
);
};
export default ReadMore;
readMore.module.css
.readMoreWrapper {
margin: 0 auto;
max-width: 800px;
padding: 20px;
border: solid 1px #5599ee;
background-color: #fff;
}
.readMoreWrpapper h2 {
margin-bottom: 20px;
}
.readMoreWrpapper p {
margin-bottom: 20px;
}
.content {
max-height: 200px; /* 初期表示の高さ */
overflow: hidden;
position: relative;
transition: max-height 0.3s ease;
padding-bottom: 1rem;
}
.content.expanded {
max-height: var(--max-height, 1000px);
}
.grad-item::before {
display: block;
position: absolute;
bottom: 0;
left: 0;
content: "";
width: 100%;
height: 100px;
background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 50%, rgba(255, 255, 255, 0.9) 50%, #fff 100%);
}
.grad-item.no-gradient::before {
display: none;
}
.readMoreButton {
display: block;
min-width: 160px;
border-radius: 999px;
margin: 10px auto;
padding: 10px 20px;
background-color: #006999;
border: 1px solid #006999;
color: #fff;
border: none;
cursor: pointer;
transition: background-color 0.3s ease, color 0.3s ease;
}
.readMoreButton:hover {
background-color: #fff;
border: 1px solid #006999;
color: #006999;
}
参考サイト
ReactのuseStateについて丁寧に理解する
https://qiita.com/KokiSakano/items/c16a8daf03acdbd6c911