Reactでの複数のアコーディオンの実装ってどうやるのかな?
『よくある質問』みたいなのを実装したいんだけど。
本記事では、Reactでのアコーディオンの実装について解説していきます。
実際に動くコードも用意しておりますので、動作を確認しながら理解を深められるようになっております。
本記事の信頼性
30歳から異業種への転職をして、Shopify Experts企業で1年半ほどフルリモートで勤務していました。
現在は名古屋の自社開発企業のフロントエンドエンジニアしています。フリーランスとしても活動しています。
Reactもまだまだ勉強中なのでもし間違っているところなどあれば、
DMで教えてもらえるとうれしいのです。
Twitter: https://twitter.com/oka_jumboworld
最終の実装イメージとコード
export default function App() {
const [openAnswer, setOpenAnswer] = useState({ 0: false });
const handleOpenAnswer = (index) => {
setOpenAnswer((prevState) => ({
...prevState,
[index]: !prevState[index]
}));
};
return (
<div className="App">
<h1>アコーディオンの実装方法</h1>
{data.faqs.map((faq, index) => {
return (
<div className="faq-item" key={index}>
<div
className="faq-item__title"
onClick={() => handleOpenAnswer(index)}
>
{faq.question}
</div>
{openAnswer[index] ? (
<div className="faq-item__description">{faq.answer}</div>
) : undefined}
</div>
);
})}
</div>
);
}
data.json (よくある質問のデータ)
{
"faqs": [
{
"question": "誕生日はいつですか?",
"answer": "1990年4月12日生まれです。32歳です。(2022年11月時点)"
},
{
"question": "なぜエンジニアを目指したのですか?",
"answer": "簡単に1,000万円稼げると聞いたので目指しました。"
},
{
"question": "エンジニアをしていて楽しいと感じるときはなんですか?",
"answer": "思っていたようにフロントの実装ができたときです。バックエンドは現在勉強中なのですが、ロジックを考える時間も楽しいです。"
},
{
"question": "これからどうなりたいですか?",
"answer": "まずはフロントエンドを極めていきたいです。バックエンドやデザイン領域にも関心があるので自分で勉強は続けていきたいです。"
}
]
}
コードの解説
よくある質問の表示部分
まずは、HTMLの作っている部分についてです。
{data.faqs.map((faq, index) => {
return (
<div className="faq-item" key={index}>
<div
className="faq-item__title"
onClick={() => handleOpenAnswer(index)}
>
{faq.question}
</div>
{openAnswer[index] ? (
<div className="faq-item__description">{faq.answer}</div>
) : undefined}
</div>
);
})}
data.json
からインポートしたデータをJavaScriptのmap関数で配列を呼び出します。data.faqs.map((faq, index)
のfaq
の中身を確認してみます。
質問(question)と回答(answer)の要素を取得して表示します。
<div className="faq-item" key={index}>
<div className="faq-item__title">{faq.question}</div>
<div className="faq-item__description">{faq.answer}</div>
</div>
これで画面部分の実装は完了です。
クリックしたときに表示・非表示を制御する
まずは、質問の要素をクリックしたときのイベントを取得しますconsole.log
で確認する。
<div
className="faq-item__title"
onClick={() => handleOpenAnswer(index)}
>
{faq.question}
</div>
const handleOpenAnswer = (index) => {
console.log(`${index}番目をクリック!!`);
};
次の実装が本題の部分になってきます。
表示・非表示の状態管理についてはuseState
で行います。
const [openAnswer, setOpenAnswer] = useState({ 0: false });
const handleOpenAnswer = (index) => {
setOpenAnswer((prevState) => ({
...prevState,
[index]: !prevState[index]
}));
};
openAnswerがState変数、setOpenAnswerがStateを更新するための関数になります。
クリックしたときにsetOpenAnswer
関数でオブジェクトを更新します。
prevState
には更新前のStateが入っているので最初の状態ですと{ 0: false }が入っています。
...prevState
の...
とはスプレッド構文といいます。大括弧[]や中括弧{}を外してくれることで配列やハッシュ構造を展開してくれます。
クリックした要素ののboolean値を反転させてStateに保持するために[index]: !prevState[index]
の記述を行います。
!prevState[index]
の[index]
が実はよく意味が分かっていない、、、。
これでopenAnswerの値をconsole.logで確認します。
あとは、条件分岐を追加することで表示・非表示を制御することが可能です。
ここでは、三項演算子で実装しています。
openAnswer[index]でどの質問なのかを判定して出し分けを行っております。
{openAnswer[index] ? (
<div className="faq-item__description">{faq.answer}</div>
) : undefined}
まとめ
なんとか実装はできても、100%挙動が理解できていないのが悔しいですがまずはOKとしましょう。(自分に甘い)
また、実はこの実装をTypeScript
でやっていたのですがそのときにかなりハマってしまったのでその記事もどこかで書ければと思っています。
Reactの学習のオススメの教材です^^
始めの一歩
モダンJavaScriptの基礎から始める挫折しないためのReact入門
ステップアップのための教材
Reactに入門した人のためのもっとReactが楽しくなるステップアップコース完全版