🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Material-UI

Material-UIは、Material Designを利用可能なオープンソースのReact向けUIコンポーネントキットです。

JavaScript

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

React.js

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

Q&A

解決済

2回答

4114閲覧

Material-UIのTableの中にDialogを入れたときに、Dialogの中身を思った通りに表示できない

TTaro

総合スコア7

Material-UI

Material-UIは、Material Designを利用可能なオープンソースのReact向けUIコンポーネントキットです。

JavaScript

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

React.js

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

0グッド

0クリップ

投稿2019/11/30 08:09

はじめて質問させていただきます。

Reactを使ってアプリを作っています。

peopleという配列の中身を、material-uiのTableを用いて表示するというものです。

作っているうちにわからないことがありました。

まずはソースを見てください。

(2つ以上returnがあったらシンタックスハイライトが効かない?っぽかったので見づらいですが2つにわけました。上下合わせて1つのソースです。間違ったことをしていたらごめんなさい。)

js

1import React from 'react'; 2import Table from '@material-ui/core/Table'; 3import TableBody from '@material-ui/core/TableBody'; 4import TableCell from '@material-ui/core/TableCell'; 5import TableRow from '@material-ui/core/TableRow'; 6import ListIcon from '@material-ui/icons/List'; 7import IconButton from '@material-ui/core/IconButton'; 8import List from '@material-ui/core/List'; 9import ListItem from '@material-ui/core/ListItem'; 10import ListItemText from '@material-ui/core/ListItemText'; 11import Dialog from '@material-ui/core/Dialog'; 12import DialogTitle from '@material-ui/core/DialogTitle'; 13import DialogContent from '@material-ui/core/DialogContent'; 14 15 16const people = [ 17 { id: '1', name: 'taro', item: ['りんご', 'みかん'] }, 18 { id: '2', name: 'hanako', item: ['もも', 'なし'] }, 19 { id: '3', name: 'takashi', item: ['ぶどう', 'メロン'] }, 20]; 21 22function SimpleDialog(props) { 23 const { onClose, open, itemList } = props; 24 25 const handleClose = () => { 26 onClose(); 27 }; 28 29 30 return ( 31 <Dialog onClose={handleClose} aria-labelledby="person-item" open={open}> 32 <DialogTitle id="person-item">もちもの</DialogTitle> 33 <DialogContent> 34 <List> 35 {itemList.map(item => ( 36 <ListItem key={item}> 37 <ListItemText primary={item} /> 38 </ListItem> 39 ))} 40 </List> 41 </DialogContent> 42 </Dialog> 43 ); 44}

js

1export default function List(props) { 2 const [open, setOpen] = React.useState(false); 3 4 const handleClickOpen = () => { 5 setOpen(true); 6 }; 7 8 const handleClose = value => { 9 setOpen(false); 10 }; 11 12 const makeTable = people => { 13 if (people) { 14 return people.map(person => { 15 return ( 16 <TableRow hover key={person.id} tabIndex={-1}> 17 <TableCell align="center">{person.id}</TableCell> 18 <TableCell align="center">{person.name}</TableCell> 19 <TableCell> 20 <IconButton 21 onClick={handleClickOpen} 22 > 23 <ListIcon /> 24 </IconButton> 25 <SimpleDialog open={open} onClose={handleClose} itemList={person.item} /> 26 </TableCell> 27 </TableRow> 28 ); 29 }); 30 } 31 }; 32 33 return ( 34 <Table> 35 <TableBody>{makeTable(people)}</TableBody> 36 </Table> 37 );

発生している問題・実現したいこと

Tableの中に、ListIconをクリックしたら、各人のもちもの一覧を開くSimpleDialogをいれているのですが、

今現在のこのコードだと、3つあるListIconどれをクリックしてもtakashiのもちもの一覧しか表示されません。

各ボタンを押したときにきちんと各人のもちもの一覧が表示されるようにしたいです。

イメージ説明
イメージ説明

試したこと

自分の考えだと、dialogを表示する際にmapで回されて、配列の最後のオブジェクトであるtakashiのものが表示さ

れてしまっていると思ったのですが、dialogを表示したときにmapをとめる?方法がわかりませんでした。

どうかご回答の程よろしくお願いいたします。

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

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

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

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

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

guest

回答2

0

ベストアンサー

こんにちは

ご質問に挙げられているコードでは、

javascript

1const [open, setOpen] = React.useState(false);

で取得される open を、peopleの要素数分作られる <SimpleDialog> のどれに対しても prop openとして渡していますが、これだと、setOpen(true) によってopen が trueになったときに、どの<SimpleDialog> についても prop open には true が渡されます。従って、全てのダイアログが開いた状態になってしまいます。そのために結果として

3つあるListIconどれをクリックしてもtakashiのもちもの一覧しか表示されません。

という(ように見えてしまう)ことになるものと思われます。

上記を避けるための修正の一案としては、下記のように state に入れておく値を設計しなおすことが考えられます。

  • 変数名を open ではなく openId とし、その値として boolean ではなく、ダイアログを開く対象となるpeople要素のid を入れる。
  • すなわち openId"1" のときは "taro"item リストをダイアログで表示する。
  • openIdnull のとき、ダイアログは全て閉じている。これを初期値とする。

ご質問のコードにある
export default function List(props)
のコードを元に、上記の設計による修正を行ったものが、以下です。(注:名前を Listから ListApp に変えています。これは@material-ui/icons/List からimport されたListと、名前が重複するのを避けるためです。

ListApp

jsx

1export default function ListApp(props) { 2 const [openId, setOpenId] = React.useState(null); 3 4 const handleClickOpen = id => { 5 setOpenId(id); 6 }; 7 8 const handleClose = () => { 9 setOpenId(null); 10 }; 11 12 const makeTable = people => { 13 if (people) { 14 return people.map(person => { 15 return ( 16 <TableRow hover key={person.id} tabIndex={-1}> 17 <TableCell align="center">{person.id}</TableCell> 18 <TableCell align="center">{person.name}</TableCell> 19 <TableCell> 20 <IconButton 21 onClick={() => { 22 handleClickOpen(person.id); 23 }} 24 > 25 <ListIcon /> 26 </IconButton> 27 <SimpleDialog 28 open={openId === person.id} 29 onClose={handleClose} 30 itemList={person.item} 31 /> 32 </TableCell> 33 </TableRow> 34 ); 35 }); 36 } 37 }; 38 39 return ( 40 <Table> 41 <TableBody>{makeTable(people)}</TableBody> 42 </Table> 43 ); 44}

上記の <ListApp /> を、下記のcodesandboxにて動作確認できます。

以上、参考になれば幸いです。

追記

上記の回答に挙げたListApp のコードは、ご質問に挙げられている List のコードに対して最小限の修正をしたものですが、さらにリファクタしたものを下記に挙げます。

ListApp (修正版)

元のコードでは、makeTableという関数がListAppの中にあり、これがテーブル行の配列を返していましたが、このような関数を作るのならば、いっそのこと関数コンポーネントとして切り出そうという趣旨で、切り出す単位を一行分として、PersonRow というコンポーネントにしました。

jsx

1const PersonRow = ({ person, open, onOpen, onClose }) => ( 2 <TableRow hover tabIndex={-1}> 3 <TableCell align="center">{person.id}</TableCell> 4 <TableCell align="center">{person.name}</TableCell> 5 <TableCell> 6 <IconButton onClick={onOpen}> 7 <ListIcon /> 8 </IconButton> 9 <SimpleDialog open={open} onClose={onClose} itemList={person.item} /> 10 </TableCell> 11 </TableRow> 12);

上記の PersonRow を使い、また 配列people はpropsから受け取るようにして、ListApp は以下のようになりました。

jsx

1export default function ListApp({ people }) { 2 const [openId, setOpenId] = React.useState(null); 3 return ( 4 <Table> 5 <TableBody> 6 {people && 7 people.map(person => ( 8 <PersonRow 9 key={person.id} 10 person={person} 11 open={openId === person.id} 12 onOpen={() => { 13 setOpenId(person.id); 14 }} 15 onClose={() => { 16 setOpenId(null); 17 }} 18 /> 19 ))} 20 </TableBody> 21 </Table> 22 ); 23} 24

あくまでリファクタの一例として参考にして頂ければと思います。

投稿2019/11/30 09:27

編集2019/12/01 00:29
jun68ykt

総合スコア9058

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

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

TTaro

2019/12/01 07:29

とてもわかりやすく回答していただきありがとうございます。 無事おもいどおりに動かすことができました。 補足といいcodesandboxといい本当に丁寧にしていただいてありがとうございました。
jun68ykt

2019/12/01 09:43

どういたしまして。 > 無事おもいどおりに動かすことができました。 とのことで、よかったです????
guest

0

ダイアログが三つあって開閉をコントロールする変数がopenの一つしか無いのが問題ではないでしょうか。

投稿2019/11/30 08:27

TaniguchiTakaki

総合スコア171

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問