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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Next.js

Next.jsは、Reactを用いたサーバサイドレンダリングなどを行う軽量なフレームワークです。Zeit社が開発しており、nextコマンドでプロジェクトを作成することにより、開発環境整備が整った環境が即時に作成できます。

JavaScript

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

TypeScript

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

React.js

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

Q&A

解決済

1回答

1105閲覧

【React】子コンポーネントから親コンポーネントへStateの値を適切に変更したい

black-ddd

総合スコア74

Next.js

Next.jsは、Reactを用いたサーバサイドレンダリングなどを行う軽量なフレームワークです。Zeit社が開発しており、nextコマンドでプロジェクトを作成することにより、開発環境整備が整った環境が即時に作成できます。

JavaScript

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

TypeScript

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

React.js

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

0グッド

1クリップ

投稿2022/10/11 10:34

前提

ここに質問の内容を詳しく書いてください。
React + TypeScriptでwebサイトを作っています。

実現したいこと

アコーディオンを開閉するために、開閉をするためのstateを親コンポーネント内のuseStateで定義しているのですが、子コンポーネントでonClickをした時に変数が渡されている全てのアコーディオンが作動してしまい全てのアコーディオンが同時に開閉してしまうのですが、これを1つだけしかアコーディオンが開閉しない状態にするにはどうしてあげるのが良いのでしょうか。

理想は「クリックした要素だけアコーディオンが開き、それ以外の要素は開いていようが閉じていようがアコーディオンを閉じる」という挙動を実現したいです。

該当のソースコード

parentComponent

1const accordionItems = { 2 accordionList: [ 3 { 4 title: "", 5 text: "", 6 }, 7 { 8 title: "", 9 text: "", 10 }, 11 { 12 title: "", 13 text: "", 14 }, 15 { 16 title: "", 17 text: "", 18 }, 19 { 20 title: "", 21 text: "", 22 }, 23 { 24 title: "", 25 text: "", 26 }, 27 { 28 title: "", 29 text: "", 30 }, 31 ], 32}; 33 34export function ParentComponent() { 35 return ( 36 <div> 37 <Accordion accordionList={accordionItems.accordionList} /> 38 </div> 39 ); 40}

childComponent

1import classes from "./index.module.scss"; 2import React from "react"; 3import { useState, useCallback, createContext } from "react"; 4import { AccordionQuestionData } from "src/components/layouts/common/accordionQuestionData"; 5 6interface accordionData { 7 title: string; 8 text: string; 9} 10interface Props { 11 accordionList: accordionData[]; 12} 13 14export const Accordion: React.VFC<Props> = React.memo(function AccordionItem( 15 props: Props 16) { 17 18 //accordionListをコピー 19 const accordionListArray = [...props.accordionList]; 20 21 //分割点を決める 22 const half = Math.ceil(accordionListArray.length / 2); 23 24 //配列を左右に分ける 25 const leftList = accordionListArray.splice(0, half); 26 const rightList = accordionListArray.splice(-half); 27 //配列要素数が奇数だった場合、小数点になる 28 //splice()は小数点を使用すると繰り上がるので片方に偏ったデータが作れる 29 30 const [openIndex, setIndex] = useState(0); 31 32 return ( 33 <div className={classes.position}> 34 <h3 className={classes.title}>よくある質問</h3> 35 <div className={classes.flexBox}> 36 <div className={classes.flex}> 37 {leftList.map((item, index) => { 38 return ( 39 <AccordionQuestionData 40 key={index} 41 title={item.title} 42 text={item.text} 43 openIndex={openIndex} 44 setIndex={setIndex} 45 /> 46 ); 47 })} 48 </div> 49 <div className={classes.flex}> 50 {rightList.map((item, index) => { 51 return ( 52 <AccordionQuestionData 53 key={(accordionListArray.length % 2 == 0) ? index + leftList.length : index + (leftList.length + 1) * 0.5} 54 title={item.title} 55 text={item.text} 56 openIndex={openIndex} 57 setIndex={setIndex} 58 /> 59 ) 60 })} 61 </div> 62 </div> 63 </div> 64 ); 65});

grandChildComponent

1import classes from "./index.module.scss"; 2import React, { useContext } from "react"; 3import { useState, useCallback } from "react"; 4 5interface Props { 6 key: number; 7 title: string; 8 text: string; 9 openIndex: number 10 setIndex: (prev: any) => void; 11} 12 13export const AccordionQuestionData: React.VFC<Props> = React.memo( 14 function AccordionQuestion(props: Props) { 15 console.log(props.key) 16 //ここで値を変更させて同一の変数を扱いつつ、それぞれの範囲内でクリック判定を扱えるようにする 17 18 const changeIndex = useCallback((index: number) => { 19 props.setIndex((prev: any) => { 20 return prev === index ? -1 : index; 21 }) 22 }, [props]) 23 24 25 return ( 26 <div className={classes.accordionWrapper}> 27 <div 28 className={`${classes.accordionTitle} ${ 29 props.openIndex === props.key ? classes.open : "" 30 }`} 31 onClick={(e) => { 32 e.preventDefault(); 33 changeIndex(props.key); 34 //ここで開閉イベントを行う 35 }} 36 > 37 <p>{props.title}</p> 38 </div> 39 <div 40 className={`${classes.accordionItem} ${ 41 props.openIndex === props.key ? "" : classes.collapsed 42 }`} 43 > 44 <div className={classes.accordionContent}> 45 <p 46 className={classes.accordionText} 47 dangerouslySetInnerHTML={{ 48 __html: props.text, 49 }} 50 ></p> 51 </div> 52 </div> 53 </div> 54 ); 55 } 56); 57

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

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

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

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

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

guest

回答1

0

ベストアンサー

keyという名前のPropは、Reactが特別にハンドリングするため、子コンポーネントでは受け取れません

key は React へのヒントとして使われますが、あなたが書くコンポーネントには渡されません。(React公式より)

渡されないkeyを使って制御を組んだために、openIndexundefinedとなって「全部開く」ような挙動に陥ったものと思われます。

投稿2022/10/11 22:34

maisumakun

総合スコア145184

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問