基于React与Material-UI的Web表单确认页面实现咨询
Got it, let's fix this confirmation page issue. The core problem here is that you're not storing the user's input anywhere—so when you get to step 3, there's no data to display. Here's a complete, step-by-step solution:
1. Add State to Track Form Data
First, we need a state object in your Content component to store all user inputs across every step. Initialize it with default values matching each field in your form.
2. Bind Inputs to Update State
Modify each form component (RadioGroups, Selects, TextField) to update the state whenever the user makes a selection or types. We'll use onChange handlers for this.
3. Render Saved Data in the Confirmation Step
Update the case 3 section of getStepContent to display the values stored in state instead of just labels, converting raw values to human-readable text where needed.
Modified Content.js Code
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, formContext) { // Pass state and setter as context const { formData, setFormData } = formContext; switch (stepIndex) { case 0: return ( <> <div> <FormControl component="fieldset"> <FormLabel component="legend">- 性别 -</FormLabel> <RadioGroup row aria-label="gender" name="row-radio-buttons-group" value={formData.gender || ""} onChange={(e) => setFormData(prev => ({...prev, gender: e.target.value}))} > <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="birth-year">year</InputLabel> <Select native defaultValue="" id="birth-year" label="Grouping" value={formData.birthYear || ""} onChange={(e) => setFormData(prev => ({...prev, birthYear: e.target.value}))} > <option aria-label="None" value="" /> <optgroup label="year"> {Array.from(Array(2020), (_, num) => ( <option key={num} value={num + 1}> {num + 1990} </option> ))} </optgroup> </Select> </FormControl> <FormControl sx={{ m: 1, minWidth: 120 }}> <InputLabel htmlFor="birth-month">month</InputLabel> <Select native defaultValue="" id="birth-month" label="Grouping" value={formData.birthMonth || ""} onChange={(e) => setFormData(prev => ({...prev, birthMonth: e.target.value}))} > <option aria-label="None" value="" /> <optgroup label="month"> {Array.from(Array(12), (_, num) => ( <option key={num} value={num + 1}> {num + 1} </option> ))} </optgroup> </Select> </FormControl> <FormControl sx={{ m: 1, minWidth: 120 }}> <InputLabel htmlFor="birth-day">day</InputLabel> <Select native defaultValue="" id="birth-day" label="Grouping" value={formData.birthDay || ""} onChange={(e) => setFormData(prev => ({...prev, birthDay: e.target.value}))} > <option aria-label="None" value="" /> <optgroup label="day"> {Array.from(Array(31), (_, num) => ( <option key={num} value={num + 1}> {num + 1} </option> ))} </optgroup> </Select> </FormControl> </div> </> ); case 1: return ( <div> <FormControl component="fieldset"> <FormLabel component="legend">您目前是否已加入人寿保险?</FormLabel> <RadioGroup row aria-label="hasInsurance" name="hasInsurance" value={formData.hasInsurance || ""} onChange={(e) => setFormData(prev => ({...prev, hasInsurance: e.target.value}))} > <FormControlLabel value="yes" control={<Radio />} label="是" /> <FormControlLabel value="no" control={<Radio />} label="否" /> </RadioGroup> <FormLabel component="legend"> 您目前是否正在住院?或者在3个月内,是否有过经医师诊断/检查后被建议住院或手术的情况? </FormLabel> <RadioGroup row aria-label="isHospitalized" name="isHospitalized" value={formData.isHospitalized || ""} onChange={(e) => setFormData(prev => ({...prev, isHospitalized: e.target.value}))} > <FormControlLabel value="yes" control={<Radio />} label="是" /> <FormControlLabel value="no" control={<Radio />} label="否" /> </RadioGroup> <FormLabel component="legend"> 过去5年内,您是否因疾病或受伤接受过手术,或有过连续7天以上的住院经历? </FormLabel> <RadioGroup row aria-label="hadSurgery" name="hadSurgery" value={formData.hadSurgery || ""} onChange={(e) => setFormData(prev => ({...prev, hadSurgery: e.target.value}))} > <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="如有其他需求等,请在此填写" value={formData.consultation || ""} onChange={(e) => setFormData(prev => ({...prev, consultation: e.target.value}))} /> </Tooltip> </Grid> </Grid> ); case 3: // Convert raw values to readable text const genderText = formData.gender === "male" ? "男" : formData.gender === "female" ? "女" : "未填写"; const birthDate = formData.birthYear && formData.birthMonth && formData.birthDay ? `${parseInt(formData.birthYear) + 1989}年${formData.birthMonth}月${formData.birthDay}日` : "未填写"; const yesNoText = (value) => value === "yes" ? "是" : value === "no" ? "否" : "未填写"; return ( <div style={{ lineHeight: "2.5", marginTop: 20 }}> <Typography variant="h6" gutterBottom>您填写的信息如下:</Typography> <div> <strong>- 性别 -</strong> {genderText} </div> <div> <strong>- 出生日期 -</strong> {birthDate} </div> <div> <strong>您目前是否已加入人寿保险?</strong> {yesNoText(formData.hasInsurance)} </div> <div> <strong>您目前是否正在住院?或者在3个月内,是否有过经医师诊断/检查后被建议住院或手术的情况?</strong> {yesNoText(formData.isHospitalized)} </div> <div> <strong>过去5年内,您是否因疾病或受伤接受过手术,或有过连续7天以上的住院经历?</strong> {yesNoText(formData.hadSurgery)} </div> <div style={{ marginTop: 10 }}> <strong>- 咨询内容 -</strong> <p style={{ marginLeft: 10, whiteSpace: "pre-wrap", marginTop: 5 }}>{formData.consultation || "未填写"}</p> </div> </div> ); default: return "Unknown stepIndex"; } } function Content() { const [activeStep, setActiveStep] = React.useState(0); // Initialize form data state const [formData, setFormData] = React.useState({ gender: "", birthYear: "", birthMonth: "", birthDay: "", hasInsurance: "", isHospitalized: "", hadSurgery: "", consultation: "" }); const steps = getSteps(); const handleNext = () => { // Optional: Add validation here to block empty required fields setActiveStep((prevActiveStep) => prevActiveStep + 1); }; const handleBack = () => { setActiveStep((prevActiveStep) => prevActiveStep - 1); }; const handleReset = () => { setActiveStep(0); // Reset all form data setFormData({ gender: "", birthYear: "", birthMonth: "", birthDay: "", hasInsurance: "", isHospitalized: "", hadSurgery: "", consultation: "" }); }; 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, { formData, setFormData })}</Typography> <Button disabled={activeStep === 0} onClick={handleBack} style={{ marginRight: 10 }}> 返回 </Button> <Button variant="contained" color="primary" onClick={handleNext}> {activeStep === steps.length - 1 ? "提交" : "下一步"} </Button> </div> )} </Grid> </Grid> ); } export default Content;
Key Changes Explained
- Form State Management: We added
formDatastate to persist every user input. This ensures data stays intact as users navigate between steps. - Input Binding: Each form component now uses
valueto reflect the current state andonChangeto update the state when the user interacts with it. - Confirmation Display: In case 3, we convert raw state values (like "male" or "yes") into user-friendly text and display each field with its original label.
- Reset Functionality: The
handleResetnow clears both the active step and all form data, giving users a fresh start.
Optional Enhancements
- Add form validation in
handleNextto prevent users from advancing without filling required fields. - Use
useReducerinstead ofuseStateif your form grows more complex (thoughuseStateworks perfectly for this use case).
内容的提问来源于stack exchange,提问作者masaomi

