【问题标题】:How to validate each form step in material ui stepper?如何验证material ui stepper中的每个表单步骤?
【发布时间】:2020-05-18 15:01:38
【问题描述】:

下面的典型材质-ui 步进器。

  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>
    );
}

这是我为选择步骤创建的函数

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';
    }
}

Step1 和 Step2 是使用 react-final-form 构建的内部有 2 个表单的组件

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>
                )}
            />
        )
    }
}

问题来了。 Material ui stepper 有handleNext 功能。它是我为每个步骤提交的。每个步骤都将是某种带有验证的表单。当用户在第 1 步并按下提交时,我想向他展示输入错误(需要某些内容等)并防止跳转到下一步。 Step1 可以有多个小表单,因此当按下 handleNext 时,应验证所有表单。

【问题讨论】:

    标签: reactjs material-ui react-final-form


    【解决方案1】:

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

    1. 用表单(而不是 div)包装页面
    2. 使用“useRef”反应挂钩设置对表单的引用
    3. 在“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>
        );
    }
    

    【讨论】:

      【解决方案2】:

      我想出的逐步验证的最佳方法是将表单分解为小表单,并让控制器组件将所有表单值组合在一起,就像在 Wizard Form Example 中一样。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-07-08
        • 1970-01-01
        • 2020-02-27
        • 1970-01-01
        • 1970-01-01
        • 2022-01-02
        • 2019-04-01
        • 2018-12-31
        相关资源
        最近更新 更多