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

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

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

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

React.js

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

Q&A

解決済

1回答

2076閲覧

【React】アンケート画面で質問に答えると次の質問が表示されるように実装したい

edu

総合スコア35

Material-UI

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

React.js

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

0グッド

0クリップ

投稿2021/10/23 07:14

編集2021/10/23 13:22

ReactでMaterial-UI を使用して、Web フォームを作成しています。

アンケート画面で、3つの質問が表示されるのを
『最初に表示されている質問は1つのみでラジオボタンをクリックして質問に答えると2つ目の質問が表示され
ラジオボタンをクリックして質問に答えると最終的に3つの質問が表示される』ように実装したいです。

色々調べたのですが、どのように実装したら良いかわからない状況で、詰まっています。
何方かアドバイスをお願いします。

期待する動作
components / Content.js の case 1: 以下内
アンケート画面で、3つの質問があるが、最初に表示されている質問は1つのみでラジオボタンをクリックして質問に答えると2つ目の質問が表示されラジオボタンをクリックして質問に答えると最終的に3つの質問が表示されるように実装したい。

現在の状況及び問題解決のために行ったこと
① Material-UI /trap focusを使用したが、現在、Material-UI /radio buttonを使っていて、融合した実装ができなかった。
② 下記のフォームとイベントハンドリングを使用したがうまく実装できなかった。

const [val, setVal] = React.useState(''); const handleChange = e => setVal(e.target.value);

###index.js

import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root') ); reportWebVitals();

###App.js

import "./App.css"; import { Grid } from "@mui/material"; import Header from "./components/Header"; import Content from "./components/Content"; function App() { return ( <Grid container direction="column"> <Header /> <div style={{ padding: 30 }}> <Content /> </div> </Grid> ); } export default App;

###// src / components / contents.js

import React from "react"; import { Grid } from "@mui/material"; import Stepper from "@mui/material/Stepper"; import Step from "@mui/material/Step"; import StepLabel from "@mui/material/StepLabel"; import Button from "@mui/material/Button"; import Typography from "@mui/material/Typography"; import Radio from "@mui/material/Radio"; import RadioGroup from "@mui/material/RadioGroup"; import FormControlLabel from "@mui/material/FormControlLabel"; import FormControl from "@mui/material/FormControl"; import FormLabel from "@mui/material/FormLabel"; import Tooltip from "@mui/material/Tooltip"; import TextField from "@mui/material/TextField"; import InputLabel from "@mui/material/InputLabel"; import Select from "@mui/material/Select"; function getSteps() { return ["お客様の情報を入力してください", "以下にお答えください", "ご相談ください"]; } function getStepContent(stepIndex) { switch (stepIndex) { case 0: return ( <> <div> <FormControl component="fieldset"> <FormLabel component="legend">- 性別 -</FormLabel> <RadioGroup row aria-label="gender" name="row-radio-buttons-group"> <FormControlLabel value="male" control={<Radio />} label="男性" /> <FormControlLabel value="female" control={<Radio />} label="女性" /> </RadioGroup> </FormControl> </div> <div> <FormLabel component="legend">- 生年月日 -</FormLabel> <FormControl sx={{ m: 1, minWidth: 120 }}> <InputLabel htmlFor="grouped-native-select">year</InputLabel> <Select native defaultValue="" id="grouped-native-select" label="Grouping"> <option aria-label="None" value="" /> <optgroup label="year"> <option value={1}> 1990</option> </optgroup> </Select> </FormControl> <FormControl sx={{ m: 1, minWidth: 120 }}> <InputLabel htmlFor="grouped-native-select">month</InputLabel> <Select native defaultValue="" id="grouped-native-select" label="Grouping"> <option aria-label="None" value="" /> <optgroup label="month"> <option value={1}> 1</option> <option value={2}> 2</option> <option value={3}> 3</option> <option value={4}> 4</option> <option value={5}> 5</option> <option value={6}> 6</option> <option value={7}> 7</option> <option value={8}> 8</option> <option value={9}> 9</option> <option value={10}> 10</option> <option value={11}> 11</option> <option value={12}> 12</option> </optgroup> </Select> </FormControl> <FormControl sx={{ m: 1, minWidth: 120 }}> <InputLabel htmlFor="grouped-native-select">day</InputLabel> <Select native defaultValue="" id="grouped-native-select" label="Grouping"> <option aria-label="None" value="" /> <optgroup label="day"> <option value={1}> 1</option> <option value={2}> 2</option> <option value={3}> 3</option> </optgroup> </Select> </FormControl> </div> </> ); //アンケート画面 case 1: return ( <div> <FormControl component="fieldset"> <FormLabel component="legend">現在、生命保険に加入されていますか?</FormLabel> <RadioGroup row aria-label="gender" name="row-radio-buttons-group"> <FormControlLabel value="yes" control={<Radio />} label="はい" /> <FormControlLabel value="no" control={<Radio />} label="いいえ" /> </RadioGroup> <FormLabel component="legend"> 現在、入院中ですか。また、3ヶ月以内に医師の診察・検査の結果、入院・手術をすすめられたことがありますか? </FormLabel> <RadioGroup row aria-label="gender" name="row-radio-buttons-group"> <FormControlLabel value="yes" control={<Radio />} label="はい" /> <FormControlLabel value="no" control={<Radio />} label="いいえ" /> </RadioGroup> <FormLabel component="legend"> 過去、5年以内に病気やケガで手術を受けたことまたは継続して7日以上の入院をしたことはありますか? </FormLabel> <RadioGroup row aria-label="gender" name="row-radio-buttons-group"> <FormControlLabel value="yes" control={<Radio />} label="はい" /> <FormControlLabel value="no" control={<Radio />} label="いいえ" /> </RadioGroup> </FormControl> </div> ); case 2: return ( <Grid container> <Grid sm={2} /> <Grid lg={8} sm={8} spacing={10}> <Tooltip title="ご相談内容を記入することができます" placement="top-start" arrow> <TextField label="ご相談内容" fullWidth margin="normal" rows={4} multiline variant="outlined" placeholder="その他ご要望等あれば、ご記入ください" /> </Tooltip> </Grid> </Grid> ); default: return "Unknown stepIndex"; } } function Content() { const [activeStep, setActiveStep] = React.useState(0); const steps = getSteps(); const handleNext = () => { setActiveStep((prevActiveStep) => prevActiveStep + 1); }; const handleBack = () => { setActiveStep((prevActiveStep) => prevActiveStep - 1); }; const handleReset = () => { setActiveStep(0); }; return ( <Grid container> <Grid sm={2} /> <Grid lg={8} sm={8} spacing={10}> <Stepper activeStep={activeStep} alternativeLabel> {steps.map((label) => ( <Step key={label}> <StepLabel>{label}</StepLabel> </Step> ))} </Stepper> {activeStep === steps.length ? ( <div> <Typography>全ステップの表示を完了</Typography> <Button onClick={handleReset}>リセット</Button> </div> ) : ( <div> <Typography>{getStepContent(activeStep)}</Typography> <Button disabled={activeStep === 0} onClick={handleBack}> 戻る </Button> <Button variant="contained" color="primary" onClick={handleNext}> {activeStep === steps.length - 1 ? "送信" : "次へ"} </Button> </div> )} </Grid> </Grid> ); } export default Content;

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

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

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

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

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

guest

回答1

0

ベストアンサー

ひとつの修正案として回答します。

大きな修正点としては、

  1. switch (stepIndex)case 1:でreturnしていたコンポーネント全体を、個別のコンポーネント Questionnaire として切り出したこと
  2. Content のstate として、アンケートの各設問の回答を配列answersを持たせるようにして、この配列と配列を更新する関数 setAnswersを props 経由で、Questionnaireコンポーネントまで渡すようにしたこと
  3. 関数であったgetStepContentを、StepContentコンポーネントにした。

です。

修正後のsrc/components/contents.js 全体は以下です。丸っとコピペして、git diffなどで差分をご確認ください。

import React from "react"; import { Grid } from "@mui/material"; import Stepper from "@mui/material/Stepper"; import Step from "@mui/material/Step"; import StepLabel from "@mui/material/StepLabel"; import Button from "@mui/material/Button"; import Typography from "@mui/material/Typography"; import Radio from "@mui/material/Radio"; import RadioGroup from "@mui/material/RadioGroup"; import FormControlLabel from "@mui/material/FormControlLabel"; import FormControl from "@mui/material/FormControl"; import FormLabel from "@mui/material/FormLabel"; import Tooltip from "@mui/material/Tooltip"; import TextField from "@mui/material/TextField"; import InputLabel from "@mui/material/InputLabel"; import Select from "@mui/material/Select"; const QUESTIONS = [ '現在、生命保険に加入されていますか?', '現在、入院中ですか。また、3ヶ月以内に医師の診察・検査の結果、入院・手術をすすめられたことがありますか?', '過去、5年以内に病気やケガで手術を受けたことまたは継続して7日以上の入院をしたことはありますか?', ]; const Questionnaire = ({ answers, setAnswers }) => { const handleAnswer = (answeredIndex, answer) => { setAnswers(answers.map(((e, i) => i === answeredIndex ? answer : e))); } return ( <div> <FormControl component="fieldset"> {answers .filter((_, i ) => i === 0 || answers[i-1]) .map((answer, i) => ( <React.Fragment key={i}> <FormLabel component="legend">{QUESTIONS[i]}</FormLabel> {answer ? <Typography>{answer === 'yes' ? 'はい' : 'いいえ'}</Typography> : ( <RadioGroup row aria-label="gender" name="row-radio-buttons-group" onChange={(_evt, value) => { handleAnswer(i, value); }}> <FormControlLabel value="yes" control={<Radio/>} label="はい"/> <FormControlLabel value="no" control={<Radio/>} label="いいえ"/> </RadioGroup> )} </React.Fragment> ))} </FormControl> </div> ); } function getSteps() { return ["お客様の情報を入力してください", "以下にお答えください", "ご相談ください"]; } const StepContent = ({ stepIndex, questionnaireProps }) => { switch (stepIndex) { case 0: return ( <> <div> <FormControl component="fieldset"> <FormLabel component="legend">- 性別 -</FormLabel> <RadioGroup row aria-label="gender" name="row-radio-buttons-group"> <FormControlLabel value="male" control={<Radio />} label="男性" /> <FormControlLabel value="female" control={<Radio />} label="女性" /> </RadioGroup> </FormControl> </div> <div> <FormLabel component="legend">- 生年月日 -</FormLabel> <FormControl sx={{ m: 1, minWidth: 120 }}> <InputLabel htmlFor="grouped-native-select">year</InputLabel> <Select native defaultValue="" id="grouped-native-select" label="Grouping"> <option aria-label="None" value="" /> <optgroup label="year"> <option value={1}> 1990</option> </optgroup> </Select> </FormControl> <FormControl sx={{ m: 1, minWidth: 120 }}> <InputLabel htmlFor="grouped-native-select">month</InputLabel> <Select native defaultValue="" id="grouped-native-select" label="Grouping"> <option aria-label="None" value="" /> <optgroup label="month"> <option value={1}> 1</option> <option value={2}> 2</option> <option value={3}> 3</option> <option value={4}> 4</option> <option value={5}> 5</option> <option value={6}> 6</option> <option value={7}> 7</option> <option value={8}> 8</option> <option value={9}> 9</option> <option value={10}> 10</option> <option value={11}> 11</option> <option value={12}> 12</option> </optgroup> </Select> </FormControl> <FormControl sx={{ m: 1, minWidth: 120 }}> <InputLabel htmlFor="grouped-native-select">day</InputLabel> <Select native defaultValue="" id="grouped-native-select" label="Grouping"> <option aria-label="None" value="" /> <optgroup label="day"> <option value={1}> 1</option> <option value={2}> 2</option> <option value={3}> 3</option> </optgroup> </Select> </FormControl> </div> </> ); case 1: return <Questionnaire {...questionnaireProps} />; case 2: return ( <Grid container> <Grid sm={2} /> <Grid lg={8} sm={8} spacing={10}> <Tooltip title="ご相談内容を記入することができます" placement="top-start" arrow> <TextField label="ご相談内容" fullWidth margin="normal" rows={4} multiline variant="outlined" placeholder="その他ご要望等あれば、ご記入ください" /> </Tooltip> </Grid> </Grid> ); default: return "Unknown stepIndex"; } } function Content() { const [activeStep, setActiveStep] = React.useState(0); const [answers, setAnswers] = React.useState(Array(QUESTIONS.length).fill(null)); const steps = getSteps(); const handleNext = () => { setActiveStep((prevActiveStep) => prevActiveStep + 1); }; const handleBack = () => { setActiveStep((prevActiveStep) => prevActiveStep - 1); }; const handleReset = () => { setActiveStep(0); }; const buttonDisabled = activeStep === 1 && answers.some(a => !a); return ( <Grid container> <Grid sm={2} /> <Grid lg={8} sm={8} spacing={10}> <Stepper activeStep={activeStep} alternativeLabel> {steps.map((label) => ( <Step key={label}> <StepLabel>{label}</StepLabel> </Step> ))} </Stepper> {activeStep === steps.length ? ( <div> <Typography>全ステップの表示を完了</Typography> <Button onClick={handleReset}>リセット</Button> </div> ) : ( <div> <Typography> <StepContent stepIndex={activeStep} questionnaireProps={{ answers, setAnswers }} /> </Typography> <Button disabled={activeStep === 0} onClick={handleBack}> 戻る </Button> <Button variant="contained" color="primary" onClick={handleNext} disabled={buttonDisabled}> {activeStep === steps.length - 1 ? "送信" : "次へ"} </Button> </div> )} </Grid> </Grid> ); } export default Content;

投稿2021/10/23 13:55

編集2021/10/23 14:00
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

edu

2021/10/24 05:23

kilesaさん、丁寧な解説付きの回答、ありがとうございます! 無事、解決することができました! 本当にありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問