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

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

新規登録して質問してみよう
ただいま回答率
85.35%
多次元配列

1次元配列内にさらに配列を格納している配列を、多次元配列と呼びます。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

React.js

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

Q&A

解決済

1回答

2093閲覧

Reactで、配列の配列を、孫コンポーネントで出力したい

masaking

総合スコア30

多次元配列

1次元配列内にさらに配列を格納している配列を、多次元配列と呼びます。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

React.js

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

0グッド

1クリップ

投稿2020/03/28 23:31

MERNスタック、という言葉を知り、まずはExpressとReactそれぞれでデータを出力することにトライしています。
expressではできました。
しかし、Reactで、各ビッグファイブの属性のchildrenのname及びpercentileを、modalで、各Big5をクリックしたときに出力することができません。

データの置き場所や、コンポーネントの構成など、根本的なところが間違っているのか、データの引継ぎ方が間違っているのか、ご指摘いただきたいです。

big5page.js

big5page.js

1import React, { useEffect, useState} from 'react'; 2import { 3 Button, 4 Badge, 5 CardColumns 6} from 'react-bootstrap'; 7 8import { useHttpClient } from '../../shared/hooks/http-hook'; 9import Big5List from '../components/Big5List.js'; 10 11 12const Big5s = () => { 13 const [loadedBig5, setLoadedBig5s] = useState(); 14 const { isLoading, error, sendRequest, clearError } = useHttpClient(); 15 16 var big5s = { 17 personality : [ 18 { 19 "trait_id": "big5_openness", 20 "name": "知的好奇心", 21 "category": "personality", 22 "percentile": 0.8479480994964365, 23 "significant": true, 24 "children": [ 25 { 26 "trait_id": "facet_adventurousness", 27 "name": "大胆性", 28 "category": "personality", 29 "percentile": 0.7360829044915548, 30 "significant": true 31 }, 32 { 33 "trait_id": "facet_artistic_interests", 34 "name": "芸術的関心度", 35 "category": "personality", 36 "percentile": 0.4201330922838075, 37 "significant": true 38 }, 39 { 40 "trait_id": "facet_emotionality", 41 "name": "情動性", 42 "category": "personality", 43 "percentile": 0.11549813941234521, 44 "significant": true 45 }, 46 { 47 "trait_id": "facet_imagination", 48 "name": "想像力", 49 "category": "personality", 50 "percentile": 0.5857506181407868, 51 "significant": true 52 }, 53 { 54 "trait_id": "facet_intellect", 55 "name": "思考力", 56 "category": "personality", 57 "percentile": 0.8961197587759683, 58 "significant": true 59 }, 60 { 61 "trait_id": "facet_liberalism", 62 "name": "現状打破", 63 "category": "personality", 64 "percentile": 0.47288657009870294, 65 "significant": true 66 } 67 ] 68 }, 69 (中略) 70 ] 71 } 72/* 73 useEffect(()=>{ 74 const fetchBig5 = async () => { 75 const responseData = await sendRequest( 76 `http://localhost:5000/api/` 77 ); 78 setLoadedBig5s(responseData.Big5s); 79 }; 80 fetchBig5(); 81 }); 82*/ 83 84 return( 85 <div> 86 <CardColumns> 87 <Big5List items={big5s} /> 88 </CardColumns> 89 90 </div> 91 ); 92}; 93 94export default Big5s;

Big5List.js

Big5List.js

1import React from 'react'; 2 3import Big5Item from './Big5Item'; 4 5const Big5List = props => { 6 return ( 7 <ul> 8 {props.items.personality.map(big5 => ( 9 <Big5Item 10 name={big5.name} 11 trait_id={big5.trait_id} 12 percentile={big5.percentile} 13 /> 14 ))} 15 </ul> 16 ); 17}; 18 19export default Big5List;

Big5Item.js

Big5Item.js

1import React, { useState, useContext } from 'react'; 2import { Button, Card } from 'react-bootstrap'; 3 4import Big5ItemDetail from './Big5ItemDetail'; 5 6const Big5Item = props => { 7 8 return( 9 <React.Fragment> 10 <Card border="primary" style={{ width: '20rem' }} bg='light' > 11 <Card.Body> 12 <Card.Title>{props.name}</Card.Title> 13 <Card.Subtitle>{props.trait_id}</Card.Subtitle> 14 <Card.Text><h4>{props.percentile}</h4></Card.Text> 15 16 <Card.Link href="#">詳しい情報はこちら</Card.Link> 17 18 {props.items.personality.children.map(big5detail => ( 19 <Big5ItemDetail 20 name={big5detail.name} 21 trait_id={big5detail.trait_id} 22 percentile={big5detail.percentile} 23 /> 24 ))}; 25 26 </Card.Body> 27 </Card> 28 29 </React.Fragment> 30 ) 31} 32 33export default Big5Item;

Big5ItemDetail.js

Big5ItemDetail.js

1import React from 'react'; 2 3class Big5ItemDetail extends React.Component{ 4 5 constructor(props){ 6 super(props); 7 this.state = {isModalOpen:false}; 8 } 9 10 handleClickBig5(){ 11 this.setState({isModalOpen:true}); 12 } 13 14 handleClickClose(){ 15 this.setState({isModalOpen: false}); 16 } 17 18 render(){ 19 let modal; 20 21 if(this.state.isModalOpen){ 22 modal=( 23 <div> 24 <div> 25 {this.props.children.name} 26 {this.props.children.trait_id} 27 {this.props.children.percentile} 28 </div> 29 <button onClick={()=>this.handleClickClose()}> 30 閉じる 31 </button> 32 </div> 33 ); 34 } 35 36 return( 37 <div> 38 <div onClick={()=>{this.handleClickBig5()}}> 39 {this.props.children.name} 40 </div> 41 <div>{modal}</div> 42 </div> 43 ); 44 } 45} 46 47export default Big5ItemDetail;

エラーメッセージ自体は、
TypeError: Cannot read property 'personality' of undefined
Big5Item
src/big5s/components/Big5Item.js:16
13 | <Card.Subtitle>{props.trait_id}</Card.Subtitle>
14 | <Card.Text><h4>{props.percentile}</h4></Card.Text>
15 |

16 | <Card.Link href="#">詳しい情報はこちら</Card.Link>

| ^ 17 |

18 | {props.items.personality.children.map(big5detail => (
19 | <Big5ItemDetail

とでているのですが、Big5Listではpersonalityが定義されているようなので、その点が謎です。

至らない点もあるかと思いますが、ご指摘いただけると嬉しいです。

足りない情報ありましたらご連絡ください。

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

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

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

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

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

guest

回答1

0

ベストアンサー

こんにちは
masakingさんも感じられているように、

データの引継ぎ方が間違っている

ように思えます。

<Big5ItemDetail /> に、 big5s. personality[i].children の各要素、たとえば

{ "trait_id": "facet_adventurousness", "name": "大胆性", "category": "personality", "percentile": 0.7360829044915548, "significant": true },

を表示させようとするのでしたら、以下のような修正になると思います。

Big5List

<Big5Item />children を渡していないので、 prop details を追加して big5.children を渡す。(さらに prop key を追加することも推奨)

diff

1<Big5Item 2+ key={big5.name} 3 name={big5.name} 4 trait_id={big5.trait_id} 5 percentile={big5.percentile} 6+ details={big5.children} 7/>

Big5Item

先の Big5List の修正によって、Big5Item には 配列 children が、prop details に渡されてくるので、map の対象の配列を、以下のように修正(さらに <Big5ItemDetail /> に、prop key を追加することも推奨)

diff

1- {props.items.personality.children.map(big5detail => ( 2+ {props.details.map(big5detail => ( 3 <Big5ItemDetail 4+ key={big5detail.name} 5 name={big5detail.name} 6 trait_id={big5detail.trait_id} 7 percentile={big5detail.percentile} 8 /> 9))}

Big5ItemDetail

上記までの修正によって、Big5ItemDetail の props には name, trait_id, percentile が入ってくるので、これらを render の冒頭でまとめて分割代入で取得して使用する。

diff

1render() { 2+ const { name, trait_id, percentile } = this.props; 3 let modal; 4 5 if (this.state.isModalOpen) { 6 modal = ( 7 <div> 8 <div> 9- {this.props.children.name} 10+ {name} 11- {this.props.children.trait_id} 12+ {trait_id} 13- {this.props.children.percentile} 14+ {percentile} 15 </div> 16 <button onClick={() => this.handleClickClose()}>閉じる</button> 17 </div> 18 ); 19 } 20 21 return ( 22 <div> 23 <div 24 onClick={() => { 25 this.handleClickBig5(); 26 }} 27 > 28- {this.props.children.name} 29+ {name} 30 </div> 31 <div>{modal}</div> 32 </div> 33 ); 34 }

それと、これは補足になりますが、上記のようにBig5ItemDetailを修正した後、さらにリファクタさせて頂くとすれば、以下のようになります。

Big5ItemDetail(リファクタ案)

jsx

1import React from "react"; 2 3const Modal = ({ name, trait_id, percentile, onClose }) => ( 4 <div> 5 <div> 6 {name} 7 {trait_id} 8 {percentile} 9 </div> 10 <button onClick={onClose}>閉じる</button> 11 </div> 12); 13 14class Big5ItemDetail extends React.Component { 15 constructor(props) { 16 super(props); 17 this.state = { isModalOpen: false }; 18 this.handleClickBig5 = this.handleClickBig5.bind(this); 19 this.handleClickClose = this.handleClickClose.bind(this); 20 } 21 22 handleClickBig5() { 23 this.setState({ isModalOpen: true }); 24 } 25 26 handleClickClose() { 27 this.setState({ isModalOpen: false }); 28 } 29 30 render() { 31 const { name } = this.props; 32 33 return ( 34 <div> 35 <div onClick={this.handleClickBig5}>{name}</div> 36 <div> 37 {this.state.isModalOpen && ( 38 <Modal {...this.props} onClose={this.handleClickClose} /> 39 )} 40 </div> 41 </div> 42 ); 43 } 44} 45 46export default Big5ItemDetail; 47 48

特にコンストラクタの中に追加した、

this.handleClickBig5 = this.handleClickBig5.bind(this); this.handleClickClose = this.handleClickClose.bind(this);

が無いと、クリック時に意図通りの動作になりません。

動作確認用 Codesandbox  

   

上記までの修正を反映したコードを、以下に挙げておきます。

投稿2020/03/29 03:06

jun68ykt

総合スコア9058

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

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

masaking

2020/03/30 13:38

本当に丁寧に教えていただきありがとうございます....!! 孫コンポーネントにpropsを渡すときは、おじいちゃんコンポーネントで用意して、それを1世代ずつ渡してあげないといけないことを学びました。 一点だけ、 this.handleClickBig5 = this.handleClickBig5.bind(this); this.handleClickClose = this.handleClickClose.bind(this); が何を意味しているのかについて、なぜこれが必要なのか、ご教授いただけると嬉しいです!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問