我即将用 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;
我希望这不是太多的代码,并且有人了解发生了什么,也许可以提供帮助。
干杯皮特