質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

1回答

3938閲覧

[React Hooks]アコーディオンの一つ目は開いた状態 + 他のアコーディオンをクリックしたら開いてるアコーディオンを閉じたい

black-ddd

総合スコア74

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2021/10/30 03:20

前提・実現したいこと

現在、ウェブサイトの制作をしている中で、アコーディオンでの表示についての質問をさせていただきたくスレッドを立てました。
前提として、アコーディオン自体の動きの部分は実装できているのですが、

  • アコーディオンの1つ目だけ最初から開いた状態にする
  • 他のアコーディオンをクリックしたら開いているアコーディオンを閉じる

という要素に悩まされているので作り方などをお聞きできればと思います。

#実際のコード

parent

1import classes from './index.module.scss' 2import { Accordion } from './accordion' 3 4const accordionItems = [ 5 { 6 title: '', 7 text: [ 8 '', 9 ], 10 }, 11 { 12 title: '', 13 text: [ 14 '', 15 ], 16 }, 17 { 18 title: '', 19 text: [ 20 '', 21 '', 22 '', 23 ], 24 }, 25 { 26 title: '', 27 text: [ 28 '', 29 ], 30 }, 31 { 32 title: '', 33 text: [ 34 '', 35 ], 36 }, 37 { 38 title: '', 39 text: [ 40 '', 41 ], 42 }, 43 { 44 title: '', 45 text: [ 46 '', 47 ], 48 }, 49 { 50 title: '', 51 text: [ 52 '', 53 ], 54 }, 55] 56 57export function TopQuestion() { 58 59 return ( 60 <div className={classes.wrapper}> 61 <div className={classes.contents}> 62 <div className={classes.about}> 63 <div className={classes.title}> 64 <h2>質問と回答</h2> 65 <p>より多くの質問と回答はFAQからご覧ください</p> 66 </div> 67 {[...accordionItems].map((item, i) => { 68 return ( 69 <div className={classes.accordionWrapper} key={i}> 70 <Accordion title={item.title} > 71 {item.text.map((text, index) => { 72 return ( 73 <p key={index} className={classes.accordionText}> 74 {text} 75 </p> 76 ) 77 })} 78 </Accordion> 79 </div> 80 ) 81 })} 82 </div> 83 </div> 84 </div> 85 ) 86}

child

1import { useState } from 'react' 2import classes from './index.module.scss' 3 4export type Props = { 5 title: string 6 children: React.ReactNode 7} 8 9export const Accordion: React.VFC<Props> = (props) => { 10 const [isOpen, setOpen] = useState(false) 11 return ( 12 <div className={classes.accordionWrapper}> 13 <div 14 className={`${classes.accordionTitle} ${isOpen ? classes.open : ''}`} 15 onClick={() => setOpen(!isOpen)} 16 > 17 <p>{props.title}</p> 18 </div> 19 <div 20 className={`${classes.accordionItem} ${ 21 !isOpen ? classes.collapsed : '' 22 }`} 23 > 24 <div className={classes.accordionContent}> 25 <p>{props.children}</p> 26 </div> 27 </div> 28 </div> 29 ) 30} 31

#利用環境
React + TypeScript

#知りたいこと

現状はchildでsetStateによる、アコーディオンの開閉の管理とスタイルの設定などを行い、
parentにコンポーネントとして渡し、parentでは配列でアコーディオン内のタイトルと中身を設定し、
mapで配列分のアコーディオンを回し、そこにタイトルを入れて、
さらにその中でmapを回して内容を入れているという状態です。
現状でもアコーディオン自体の役割は果たせているのですが、
前提で記載した要素を行うにはどのようにHooksを駆使すれば実装することが可能なのでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2021/10/30 03:31

いまはどのように動作しているのですか?
black-ddd

2021/10/30 03:36

現状の動きですと、 初期の画面は全体的に閉じていて、押すと開く状態です。 また同じアコーディオンをクリックすれば閉じますが、 他のアコーディオンをクリックしても閉じずに開きっぱなしの状態です。 こちらからアクションを起こさないと、開かないし、閉じないという感じですね。
k4a

2021/10/30 09:05

動作を再現できるようにcssmoduleも掲載して下さい
guest

回答1

0

ベストアンサー

複数コンポーネントの状態を連動させたいのであれば、stateは上位のコンポーネントで持たなければいけません。accordionコンポーネントでそれぞれ個別で持っていてもそれが連動することはありません。

以下はあくまで一例なのでより良い方法で実装して下さい。

App

1import classes from "./index.module.scss"; 2import { Accordion } from "./accordion"; 3import { useState } from "react"; 4 5const accordionItems = [ 6 { 7 title: "1", 8 text: [""] 9 }, 10 { 11 title: "2", 12 text: [""] 13 }, 14 { 15 title: "3", 16 text: ["", "", ""] 17 }, 18 { 19 title: "4", 20 text: [""] 21 }, 22 { 23 title: "5", 24 text: [""] 25 }, 26 { 27 title: "6", 28 text: [""] 29 }, 30 { 31 title: "7", 32 text: [""] 33 }, 34 { 35 title: "8", 36 text: [""] 37 } 38]; 39 40// 最初に開いておくインデックス 41const defaultOpenIndex = 2; 42 43export default function TopQuestion() { 44 // accordionItemsと同じ数のboolean配列 45 const [openList, setOpenList] = useState(() => { 46 return accordionItems.map((v, i) => 47 i === defaultOpenIndex ? true : false 48 ); 49 }); 50 51 return ( 52 <div className={classes.wrapper}> 53 <div className={classes.contents}> 54 <div className={classes.about}> 55 <div className={classes.title}> 56 <h2>質問と回答</h2> 57 <p>より多くの質問と回答はFAQからご覧ください</p> 58 </div> 59 {[...accordionItems].map((item, i) => { 60 return ( 61 <div className={classes.accordionWrapper} key={i}> 62 <Accordion 63 title={item.title} 64 openList={openList} 65 setOpenList={setOpenList} 66 index={i} 67 > 68 {item.text.map((text, index) => { 69 return ( 70 <p key={index} className={classes.accordionText}> 71 {text} 72 </p> 73 ); 74 })} 75 </Accordion> 76 </div> 77 ); 78 })} 79 </div> 80 </div> 81 </div> 82 ); 83} 84

accordion

1import { useState } from "react"; 2import classes from "./index.module.scss"; 3 4export type Props = { 5 title: string; 6 openList: boolean[]; 7 setOpenList: React.Dispatch<React.SetStateAction<boolean[]>>; 8 index: number; 9 children: React.ReactNode; 10}; 11 12export const Accordion: React.VFC<Props> = (props) => { 13 const clickHandler = () => { 14 // クリックしたコンポーネントのインデックス以外をfalseにしてstateをセット 15 props.setOpenList( 16 props.openList.map((open, i) => (i === props.index ? !open : false)) 17 ); 18 }; 19 20 return ( 21 <div className={classes.accordionWrapper}> 22 <div 23 className={`${classes.accordionTitle} ${ 24 props.openList[props.index] ? classes.open : "" 25 }`} 26 onClick={clickHandler} 27 > 28 <p>{props.title}</p> 29 </div> 30 <div 31 className={`${classes.accordionItem} ${ 32 !props.openList[props.index] ? classes.collapsed : "" 33 }`} 34 > 35 <div className={classes.accordionContent}> 36 <div>{props.children}</div> 37 </div> 38 </div> 39 </div> 40 ); 41};

投稿2021/10/30 09:28

編集2021/10/30 09:29
k4a

総合スコア983

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

black-ddd

2021/11/01 02:48

参考になる一例をありがとうございます! useStateや継承についてもモヤモヤしていた部分でしたので助かりました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問