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

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

新規登録して質問してみよう
ただいま回答率
85.35%
Material-UI

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

React.js

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

Q&A

解決済

2回答

3191閲覧

[React]テキストフィールドの値の渡し方がわからない

aiai8976

総合スコア112

Material-UI

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

React.js

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

1グッド

1クリップ

投稿2020/03/14 14:43

前提・実現したいこと

material-uiのFormDialogを使用しているのですが、子から親コンポーネントにテキストフィールドに入力した値を渡してStateで管理する方法がわかりません。
propsは親→子だと思うので、これではできないと思います。
わかる方がいましたらコメントお願いします。

該当のソースコード

//省略 export default function Sample() { const classes = useStyles(); //省略 return ( <div className={classes.parent}> //省略 <Grid container className={classes.root_} spacing={2}> <Grid item xs={12}> <Grid container justify="center" spacing={2}> <Grid key={0} item> <FormDialog /> //該当箇所 </Grid> </Grid> </Grid> </Grid> </div> ); }
export default function FormDialog() { const [open, setOpen] = React.useState(false); const handleClickOpen = () => { setOpen(true); }; const handleClose = () => { setOpen(false); }; return ( <div> <Button variant="outlined" color="primary" onClick={handleClickOpen}> add new member </Button> <Dialog open={open} onClose={handleClose} aria-labelledby="form-dialog-title"> <DialogTitle id="form-dialog-title">名前登録</DialogTitle> <DialogContent> <DialogContentText> 名前を記入してください </DialogContentText> <TextField //対象箇所 autoFocus margin="dense" id="name" label="Name" type="email" fullWidth /> </DialogContent> <DialogActions> <Button onClick={handleClose} color="primary"> Cancel </Button> <Button onClick={handleClose} color="primary"> OK </Button> </DialogActions> </Dialog> </div> ); }
s.k👍を押しています

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

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

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

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

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

guest

回答2

0

ベストアンサー

こんにちは

親コンポーネントのstateに保持されている値を、子コンポーネントで変えるには、親コンポーネント側で、その値を変えるハンドラを用意して、これを子コンポーネントに prop 経由で渡し、子コンポーネントでそのハンドラを使うというのがお決まりのやり方です。これは Hooks が導入されてからも変わりません。

ご質問の例だと、親コンポーネントSampleの状態として持つべき(ダイアログから入力される)名前の値と、それと変更するハンドラをuseStateで取得し、それらを子コンポーネントに渡して、子ではそれらを適切に使えばよいです。

具体的な修正案を、以下のcodesandboxに挙げました。

  

上記の修正前のほうは、ご質問に挙げられているコードを転記したもので、これに適宜コードを追加して、修正後のコードを作りました。修正後では、親コンポーネントにCard を追加し、ここに子コンポーネントのダイアログから入力された名前を表示させるようにしました。

上記の修正案による、修正前と修正後の差分を以下に挙げておきます。

Sample (src/index.js)

diff

1--- before/src/index.js 2020-03-15 00:23:00.000000000 +0900 2+++ after/src/index.js 2020-03-15 00:10:28.000000000 +0900 3@@ -1,23 +1,43 @@ 4-import React from "react"; 5+import React, { useState } from "react"; 6 import ReactDOM from "react-dom"; 7 import Grid from "@material-ui/core/Grid"; 8+import Card from "@material-ui/core/Card"; 9+import CardContent from "@material-ui/core/CardContent"; 10 import { makeStyles } from "@material-ui/styles"; 11 import FormDialog from "./FormDialog"; 12 13 const useStyles = makeStyles({ 14 parent: {}, 15- root_: {} 16+ root_: {}, 17+ result: { 18+ backgroundColor: "#eee", 19+ marginBottom: 30 20+ }, 21+ name: { 22+ fontWeight: "bold", 23+ color: "darkblue" 24+ } 25 }); 26 27 function Sample() { 28 const classes = useStyles(); 29+ const [name, setName] = useState(""); 30+ 31 return ( 32 <div className={classes.parent}> 33 <Grid container className={classes.root_} spacing={2}> 34 <Grid item xs={12}> 35+ <Card className={classes.result}> 36+ <CardContent> 37+ 入力された名前: 38+ <span className={classes.name}>{name}</span> 39+ </CardContent> 40+ </Card> 41+ </Grid> 42+ <Grid item xs={12}> 43 <Grid container justify="center" spacing={2}> 44 <Grid key={0} item> 45- <FormDialog /> 46+ <FormDialog defaultValue={name} onSubmit={setName} /> 47 </Grid> 48 </Grid> 49 </Grid>

FormDialog (src/FormDialog.jsx)

diff

1--- before/src/FormDialog.jsx 2020-03-15 00:23:00.000000000 +0900 2+++ after/src/FormDialog.jsx 2020-03-15 00:10:28.000000000 +0900 3@@ -7,14 +7,20 @@ 4 import TextField from "@material-ui/core/TextField"; 5 import DialogActions from "@material-ui/core/DialogActions"; 6 7-export default function FormDialog() { 8+export default function FormDialog({ defaultValue, onSubmit }) { 9 const [open, setOpen] = React.useState(false); 10+ const inputRef = React.useRef(null); 11 12 const handleClickOpen = () => { 13 setOpen(true); 14 }; 15 16- const handleClose = () => { 17+ const handleCancel = () => { 18+ setOpen(false); 19+ }; 20+ 21+ const handleSubmit = () => { 22+ onSubmit(inputRef.current.value); 23 setOpen(false); 24 }; 25 26@@ -25,7 +31,7 @@ 27 </Button> 28 <Dialog 29 open={open} 30- onClose={handleClose} 31+ onClose={handleCancel} 32 aria-labelledby="form-dialog-title" 33 > 34 <DialogTitle id="form-dialog-title">名前登録</DialogTitle> 35@@ -38,13 +44,15 @@ 36 label="Name" 37 type="email" 38 fullWidth 39+ defaultValue={defaultValue} 40+ inputRef={inputRef} 41 /> 42 </DialogContent> 43 <DialogActions> 44- <Button onClick={handleClose} color="primary"> 45+ <Button onClick={handleCancel} color="primary"> 46 Cancel 47 </Button> 48- <Button onClick={handleClose} color="primary"> 49+ <Button onClick={handleSubmit} color="primary"> 50 OK 51 </Button> 52 </DialogActions>

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

投稿2020/03/14 16:58

編集2020/03/15 00:51
jun68ykt

総合スコア9058

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

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

aiai8976

2020/03/15 01:10

ご丁寧な解説ありがとうございました。 非常によくわかりました。
jun68ykt

2020/03/15 01:14

どういたしまして。 > 非常によくわかりました。 とのことで、よかったです ????
aiai8976

2020/03/15 01:31 編集

実はこれでStateは変更できたのですが、親の方で再描画が実施されなくて困っています。 対象のコンポーネントをいじると再描画してくれるのですが、OKボタンを押した時点で再描画をしたいと思っています。何が原因かわかりますか?
jun68ykt

2020/03/15 01:46

なるほどですね。 そういうことでしたら、 > 親の方で再描画が実施されなくて困っています。 との問題の原因と解決を求める新たなご質問を投稿して、そこにryota8976さんのお手元のコードの現状のものをご記載頂ければと思います。 そちらの質問を私も見ますし、他の回答者様も見るので、解決が早いと思います。
guest

0

子から親へのつう親から子へコールバック関数を渡して、それを呼んでもらうようにします。

JavaScript

1export default function Sample() { 2 const [value, setValue] = useState(''); 3 //省略 4 return ( 5 // 略 6 <FormDialog setValue={setValue} /> //該当箇所

JavaScript

1export default function FormDialog({ setValue }) { 2 const [open, setOpen] = React.useState(false); 3 const [text, setText] = React.useState(''); 4 5 // 略 6 7 const handleClose = (ok) => { 8 if (ok) { 9 setValue(text); 10 } 11 setOpen(false); 12 }; 13 14 return ( 15 // 略 16 <TextField //対象箇所 17 // 略 18 text={text} 19 onChange={e => setText(e.target.value)} 20 /> 21 // 略 22 <Button onClick={e => handleClose(false)} color="primary"> 23 Cancel 24 </Button> 25 <Button onClick={e => handleClose(true)} color="primary"> 26 OK 27 </Button> 28 // 略

投稿2020/03/14 16:08

hoshi-takanori

総合スコア7901

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問