Reactjs 如何在material ui stepper中验证每个表单步骤?

Reactjs 如何在material ui stepper中验证每个表单步骤?,reactjs,material-ui,react-final-form,Reactjs,Material Ui,React Final Form,典型材料界面步进器如下 export default function HorizontalLinearStepper() { const classes = useStyles(); const [activeStep, setActiveStep] = React.useState(0); const [skipped, setSkipped] = React.useState(new Set()); const steps = getSteps();

典型材料界面步进器如下

  export default function HorizontalLinearStepper() {
    const classes = useStyles();
    const [activeStep, setActiveStep] = React.useState(0);
    const [skipped, setSkipped] = React.useState(new Set());
    const steps = getSteps();

    const isStepOptional = step => {
        return step === 1;
    };

    const isStepSkipped = step => {
        return skipped.has(step);
    };

    const handleNext = () => {
    let newSkipped = skipped;
    if (isStepSkipped(activeStep)) {
        newSkipped = new Set(newSkipped.values());
        newSkipped.delete(activeStep);
    }

    setActiveStep(prevActiveStep => prevActiveStep + 1);
    setSkipped(newSkipped);
};

const handleBack = () => {
    setActiveStep(prevActiveStep => prevActiveStep - 1);
};

const handleSkip = () => {
    if (!isStepOptional(activeStep)) {
        // You probably want to guard against something like this,
        // it should never occur unless someone's actively trying to break something.
        throw new Error("You can't skip a step that isn't optional.");
    }

    setActiveStep(prevActiveStep => prevActiveStep + 1);
    setSkipped(prevSkipped => {
        const newSkipped = new Set(prevSkipped.values());
        newSkipped.add(activeStep);
        return newSkipped;
    });
};

const handleReset = () => {
    setActiveStep(0);
};

return (
    <div className={classes.root}>
        <Stepper activeStep={activeStep}>
            {steps.map((label, index) => {
                const stepProps = {};
                const labelProps = {};
                if (isStepOptional(index)) {
                    labelProps.optional = <Typography variant="caption">Optional</Typography>;
                }
                if (isStepSkipped(index)) {
                    stepProps.completed = false;
                }
                return (
                    <Step key={label} {...stepProps}>
                        <StepLabel {...labelProps}>{label}</StepLabel>
                    </Step>
                );
            })}
        </Stepper>
        <div>
            {activeStep === steps.length ? (
                <div>
                    <Typography className={classes.instructions}>
                        All steps completed - you&apos;re finished
                    </Typography>
                    <Button onClick={handleReset} className={classes.button}>
                        Reset
                    </Button>
                </div>
            ) : (
                <div>
                    <div className={classes.instructions}>{getStepContent(activeStep)}</div>
                    <div>
                        <Button disabled={activeStep === 0} onClick={handleBack} className={classes.button}>
                            Back
                        </Button>
                        {isStepOptional(activeStep) && (
                            <Button
                                variant="contained"
                                color="primary"
                                onClick={handleSkip}
                                className={classes.button}
                            >
                                Skip
                            </Button>
                        )}

                        <Button
                            variant="contained"
                            color="primary"
                            onClick={handleNext}
                            type="submit"
                            className={classes.button}
                        >
                            {activeStep === steps.length - 1 ? 'Finish' : 'Next'}
                        </Button>
                    </div>
                </div>
            )}
        </div>
    </div>
    );
}
导出默认函数HorizontalLinearStepper(){
const classes=useStyles();
const[activeStep,setActiveStep]=React.useState(0);
const[skipped,setSkipped]=React.useState(new Set());
const steps=getSteps();
常量isStepOptional=步骤=>{
返回步骤===1;
};
常量isStepSkipped=步骤=>{
返回跳过。has(步骤);
};
常量handleNext=()=>{
让新闻剪辑=跳过;
如果(isStepSkipped(activeStep)){
newskiped=新集合(newskiped.values());
newskiped.delete(activeStep);
}
setActiveStep(prevActiveStep=>prevActiveStep+1);
设置剪辑(新闻剪辑);
};
常量把手=()=>{
setActiveStep(prevActiveStep=>prevActiveStep-1);
};
常量handleSkip=()=>{
如果(!IsStep可选(activeStep)){
//你可能想防范这样的事情,
//除非有人正积极地试图打破某些东西,否则它永远不会发生。
抛出新错误(“不能跳过非可选步骤”);
}
setActiveStep(prevActiveStep=>prevActiveStep+1);
设置跳过(已跳过=>{
const newskiped=新集合(prevSkipped.values());
添加(activeStep);
返回新闻稿;
});
};
常量handleReset=()=>{
setActiveStep(0);
};
返回(
{steps.map((标签,索引)=>{
const stepProps={};
常量labelProps={};
if(可选(索引)){
labelProps.optional=可选;
}
如果(已跳过(索引)){
stepProps.completed=false;
}
返回(
{label}
);
})}
{activeStep===steps.length(
所有步骤已完成-您已完成
重置
) : (
{getStepContent(activeStep)}
返回
{isstep可选(activeStep)&&(
跳过
)}
{activeStep===steps.length-1?'Finish':'Next'}
)}
);
}
下面是我为选择步骤创建的函数

function getStepContent(step) {
    switch (step) {
        case 0:
            return <Step1/>;
        case 1:
            return <Step2/>;
        case 2:
            return 'This is the bit I really care about!';
        default:
            return 'Unknown step';
    }
}
函数getStepContent(步骤){ 开关(步骤){ 案例0: 返回; 案例1: 返回; 案例2: return‘这是我真正关心的一点!’; 违约: 返回“未知步骤”; } } Step1和Step2是在构建内部具有2个表单和react final表单的组件

import React, { Component } from 'react';
import { Form } from 'react-final-form';
import initialValuesCreator from './creationMethods/initialValuesCreator';
import { validationCreator } from './creationMethods/validationSchemaCreator';

class CustomValidationForm extends Component {

    render() {
        const {
            config ,children, submit = () => {}
        } = this.props;

        return (
            <Form
                onSubmit={(event) => {
                    submit(event);
                }}
                initialValues={initialValuesCreator(config)}
                validate={values => validationCreator(values, config)}
                render={({handleSubmit}) => (
                    <form noValidate autoComplete={'off'} onSubmit={handleSubmit}>
                        {children}
                    </form>
                )}
            />
        )
    }
}
import React,{Component}来自'React';
从“react final Form”导入{Form};
从“/creationMethods/initialValuesCreator”导入initialValuesCreator;
从“./creationMethods/validationSchemaCreator”导入{validationCreator};
类CustomValidationForm扩展组件{
render(){
常数{
配置,子项,提交=()=>{}
}=这是道具;
返回(
{
提交(活动);
}}
initialValues={initialValuesCreator(配置)}
validate={values=>validationCreator(值,配置)}
render={({handleSubmit})=>(
{儿童}
)}
/>
)
}
}

问题来了。物料界面步进器具有handleNext功能。这是我的每一步提交。每一步都是带有验证的某种形式。当用户在第1步,他按下提交,我想向他显示输入错误(需要一些东西等),并防止跳转到下一步。Step1可以有多个小表单,因此当按下handleNext时,所有表单都应该进行验证。

我想出的进行分步验证的最佳方法是将表单拆分为多个小表单,并让一个控制器组件将所有表单值组合在一起,就像中一样。

我也在处理它 我最终做了什么来解决它:

  • 用表单(而不是div)包装页面
  • 使用“useRef”react钩子设置对表单的引用
  • 检查表单在“handleNext”方法上是否有效,如果无效则返回。对表单对象的访问由useRef钩子实现,有效性检查由函数“myForm.current.checkValidity()”进行
  • 请试一试,并让我知道它是否适合您:

    export default function HorizontalLinearStepper() {
        const classes = useStyles();
        const [activeStep, setActiveStep] = React.useState(0);
        const [skipped, setSkipped] = React.useState(new Set());
        const steps = getSteps();
    
        const myForm = React.useRef(null);
    
        const isStepOptional = step => {
            return step === 1;
        };
    
        const isStepSkipped = step => {
            return skipped.has(step);
        };
    
        const handleNext = () => {
            if (!myForm.current.checkValidity()) {
               return;
            }
            let newSkipped = skipped;
            if (isStepSkipped(activeStep)) {
                newSkipped = new Set(newSkipped.values());
                newSkipped.delete(activeStep);
            }
        
            setActiveStep(prevActiveStep => prevActiveStep + 1);
            setSkipped(newSkipped);
        };
        
        const handleBack = () => {
            setActiveStep(prevActiveStep => prevActiveStep - 1);
        };
        
        const handleSkip = () => {
            if (!isStepOptional(activeStep)) {
                // You probably want to guard against something like this,
                // it should never occur unless someone's actively trying to break something.
                throw new Error("You can't skip a step that isn't optional.");
             }
         
            setActiveStep(prevActiveStep => prevActiveStep + 1);
            setSkipped(prevSkipped => {
                const newSkipped = new Set(prevSkipped.values());
                newSkipped.add(activeStep);
                return newSkipped;
            });
        };
    
        const handleReset = () => {
            setActiveStep(0);
        };
    
    return (
        <div className={classes.root}>
            <Stepper activeStep={activeStep}>
                {steps.map((label, index) => {
                    const stepProps = {};
                    const labelProps = {};
                    if (isStepOptional(index)) {
                        labelProps.optional = <Typography variant="caption">Optional</Typography>;
                    }
                    if (isStepSkipped(index)) {
                        stepProps.completed = false;
                    }
                    return (
                        <Step key={label} {...stepProps}>
                            <StepLabel {...labelProps}>{label}</StepLabel>
                        </Step>
                    );
                })}
            </Stepper>
            <form action="/" method="POST" ref={myForm}>
                {activeStep === steps.length ? (
                    <div>
                        <Typography className={classes.instructions}>
                            All steps completed - you&apos;re finished
                        </Typography>
                        <Button onClick={handleReset} className={classes.button}>
                            Reset
                        </Button>
                    </div>
                ) : (
                    <div>
                        <div className={classes.instructions}>{getStepContent(activeStep)}</div>
                        <div>
                            <Button disabled={activeStep === 0} onClick={handleBack} className={classes.button}>
                                Back
                            </Button>
                            {isStepOptional(activeStep) && (
                                <Button
                                    variant="contained"
                                    color="primary"
                                    onClick={handleSkip}
                                    className={classes.button}
                                >
                                    Skip
                                </Button>
                            )}
    
                            <Button
                                variant="contained"
                                color="primary"
                                onClick={handleNext}
                                type="submit"
                                className={classes.button}
                            >
                                {activeStep === steps.length - 1 ? 'Finish' : 'Next'}
                            </Button>
                        </div>
                    </form>
                )}
            </div>
        </div>
        );
    }
    
    导出默认函数HorizontalLinearStepper(){
    const classes=useStyles();
    const[activeStep,setActiveStep]=React.useState(0);
    const[skipped,setSkipped]=React.useState(new Set());
    const steps=getSteps();
    const myForm=React.useRef(null);
    常量isStepOptional=步骤=>{
    返回步骤===1;
    };
    常量isStepSkipped=步骤=>{
    返回跳过。has(步骤);
    };
    常量handleNext=()=>{
    如果(!myForm.current.checkValidity()){
    返回;
    }
    让新闻剪辑=跳过;
    如果(isStepSkipped(activeStep)){
    newskiped=新集合(newskiped.values());
    newskiped.delete(activeStep);
    }
    setActiveStep(prevActiveStep=>prevActiveStep+1);
    设置剪辑(新闻剪辑);
    };
    常量把手=()=>{
    setActiveStep(prevActiveStep=>prevA