1

我即将用 formik 构建一个表单来创建客户。有一堆数据要输入,为什么我决定用步进器('@material-ui/core/stepper')。现在表单是动态的,这意味着根据步骤显示不同的表单页面。对于每个子表单/步骤,我制作了一个新组件。我明确地注意将<form onSubmit=formik.handleSubmit></form>组件包裹在我的 Stepper 周围,因此与我的 subForms 的通信沿着 props 和回调运行。

所以我的计划是使用 Stepper 中的“下一步”按钮作为提交按钮,在我的“onSubmit”函数中的每一步之后缓存子表单条目,并在最后一步将所有数据发送到我的 API。

我还没有完全完成喷气机,但是每次我进入最后一步时都会出现此错误消息:

TypeError: Cannot read property 'company' of undefined
    at C (CustomerStep.js:87)
...

Warning: An unhandled error was caught from submitForm() TypeError: Cannot read property 'company' of undefined
    at C (CustomerStep.js:87)
...

CustomerStep.js:87 是 'value={props.values.company}' 设置为我的 TextField 的道具的行。

这非常令人困惑,因为在第一步之后我不再输入组件“CustomerStep.js”。子表单中的数据被写入我的 StepperForm.js 中的“数据”状态,所以我真的没有得到错误。

这是我的一些代码:

StepperForm.js

export default function StepperForm() {

    const[data, setData] = React.useState({
        customer: {
            
        },
        contacts: [],
        locations: [],
    });
...
// other states and attributes
...

    const formik = useFormik({
        initialValues: {
            customer: {
                company: "",
                street: "",
                houseNumber: "",
                plz: "",
                location: "",
                country: "",
                homepage: "",
            }
        },
        validationSchema: validation,
        onSubmit: (values) => {
            cacheData(values);
            handleNext();

            //only submit on last step
            if(activeStep === steps.length) {   
                customerToAPI();
            }
        }
    });

    function getStepContent(step) {
        switch (step) {
            case 0:
                return <CustomerStep 
                    form={formik} 
                    values= {formik.values.customer}
                    touched={formik.touched.customer ? formik.touched.customer : formik.touched}
                    errors={formik.errors.customer ? formik.errors.customer : formik.errors} 
                    handleChange={formik.handleChange}
                />;
            case 1:
                return <ContactStep />; 
            case 2:
                return <LocationStep />;
            case 3:
                return <CheckStep />;
            default:
                return 'unknown step';
        }
    };

    const cacheData = (values) => {
        let newData = data;
        switch(activeStep) {
            case 0:
                newData.customer = values.customer;
                break;
            case 1:
                // not implemented jet
                // newData.customer = values.customer;
                break;
            case 2:
                // not implemented jet
                // newData.customer = values.customer;
                break;
            default:
                break;
        }
        setData(newData);
    }

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

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

...
// other Stepper functions
...

    return (
        <div className={classes.root}>
            <form onSubmit={formik.handleSubmit}>
                <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}>
                        Customer created.
                        </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
                            name="submit"
                            variant="contained"
                            color="primary"
                            type="submit"
                            className={classes.button}
                        >
                            {activeStep === steps.length - 1 ? 'Create customer' : 'Next step'}
                        </Button>
                        </div>
                    </div>
                    )}
                </div>
            </form>
        </div>
    );
}

CustomerStep.js

function CustomerStep(props) {
  return (
      <Box>
        <TextField
          className={style.box}
          id="inputCompany"
          name="customer.company" 
          label="Firmierung"
          onChange={props.handleChange}
          value={props.values.company} 
          error={props.touched.company && Boolean(props.errors.company)}
          helperText={props.touched.company && props.errors.company}
        />

       <TextField 
            className={style.box} 
            id="inputStreet" 
            name="customer.street"
            label="Straße" 
            onChange={props.handleChange} 
            //value={props.values.street} 
            error={props.touched.street && Boolean(props.errors.street)}
            helperText={props.touched.street && props.errors.street}
        />

        <TextField ... />

        ...
        // some more form stuff, same/similar props

      </Box>
  );
}

export default CustomerStep;

我希望这不是太多的代码,并且有人了解发生了什么,也许可以提供帮助。

干杯皮特

4

0 回答 0