gpt4 book ai didi

reactjs - 使用 React Hooks 跨 Material-UI Stepper 传递数据

转载 作者:行者123 更新时间:2023-12-05 08:51:40 24 4
gpt4 key购买 nike

我有一个多步骤表单,我想在 React 中使用 FormikMaterial-ui、功能组件和 getState 钩子(Hook)。

import React, { useState, Fragment } from 'react';
import { Button, Stepper, Step, StepLabel } from '@material-ui/core';
import FormPartA from './FormPartA';
import FormPartB from './FormPartB';
import FormPartC from './FormPartC';

function MultiStepForm(props) {

const steps = ['Part A', 'Part B', 'Part C'];
const passedValues = props.values || {};

const [activeStep, setActiveStep] = useState(0);
const [values, setValues] = useState({
field1:(( typeof passedValues.field1 === 'undefined' || passedValues.field1 === null ) ? '1' : passedValues.field1 ),
field2:(( typeof passedValues.field2 === 'undefined' || passedValues.field2 === null ) ? '2' : passedValues.field2 ),
field3:(( typeof passedValues.field3 === 'undefined' || passedValues.field3 === null ) ? '3' : passedValues.field3 ),
field4:(( typeof passedValues.field4 === 'undefined' || passedValues.field4 === null ) ? '4' : passedValues.field4 ),
field5:(( typeof passedValues.field5 === 'undefined' || passedValues.field5 === null ) ? '5' : passedValues.field5 ),
field6:(( typeof passedValues.field6 === 'undefined' || passedValues.field6 === null ) ? '6' : passedValues.field6 )
});

const handleNext = () => {
alert({...props.values, ...values});
setValues({...props.values, ...values});
setActiveStep(activeStep + 1);
};

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

function thisStep(step) {
switch (step) {
case 0:
return <FormPartA values={values} setValues={setValues}/>;
case 1:
return <FormPartB values={values} setValues={setValues}/>;
case 2:
return <FormPartC values={values} setValues={setValues}/>;
default:
throw new Error('Mis-step!');
}
}

return (
<div className="MultiStepForm">
<Stepper activeStep={activeStep} className={classes.stepper}>
{steps.map(label => (
<Step key={label}>
<StepLabel>{label}</StepLabel>
</Step>
))}
</Stepper>
<Fragment>
{activeStep === steps.length ? (
<p>You're done!<p>
) : (
<Fragment>
{thisStep(activeStep)}
<div className={classes.buttons}>
{activeStep !== 0 && (
<Button onClick={handleBack} > Back </Button>
)}
<Button onClick={handleNext} >
{activeStep === steps.length - 1 ? 'Done' : 'Next'}
</Button>
</div>
</Fragment>
)}
</Fragment>
</div>
);
}

为了便于讨论,每个子表单大致如下所示,每个子表单只有 2 个字段:

import React from 'react';

import {Formik, useField, Field, Form} from 'formik';
import { TextField } from 'formik-material-ui';
import * as Yup from "yup";
import { Button } from '@material-ui/core';

export default function BasicForm(props) {

const field1 = ( typeof props.values.field1 === 'undefined' || props.values.field1 === null ) ? '' : props.values.field1;
const field2 = ( typeof props.values.field2 === 'undefined' || props.values.field2 === null ) ? '' : props.values.field2;

return (
<div>

<h3>Part A</h3>

<Formik
initialValues={{
field1,
field2
}}
validationSchema={Yup.object({
field1: Yup.string()
.required('Required'),
field2: Yup.string()
.required('Required'),
})}
>
{({submitForm, isSubmitting, values, setFieldValue}) => (
<Form>
<Field name="field1" type="text" label="Field 1" variant="outlined"
margin="normal" fullWidth multiline component={TextField} />
<Field name="field2" type="text" label="Field 2" variant="outlined"
margin="normal" fullWidth multiline component={TextField} />
</Form>
)}
</Formik>
</div>
);
}

我无法理解的一点是状态的更新。在表单之间切换时,如何确保保存每个子表单的子状态?此外,(( typeof passedValues.field1 === 'undefined' || passedValues.field1 === null ) ? '1' : passedValues.field1 ) 构造看起来很笨拙?

最佳答案

好的,我让它工作了,这很有趣(对于小的乐趣值)。一半的问题是认识到需要将 activeStep 值、handleNext()handleBack() 函数传递给子表单, 以及预先计算是否这个 isLastStep:

import React, { useState, Fragment } from 'react';
import { Button, Stepper, Step, StepLabel } from '@material-ui/core';
import FormPartA from './FormPartA';
import FormPartB from './FormPartB';
import FormPartC from './FormPartC';

const steps = ['Part A', 'Part B', 'Part C'];

function MultiStepForm(props) {

const { field1, field2, field3, field4, field5, field6, } = props;

const [activeStep, setActiveStep] = useState(0);
const [formValues, setFormValues] = useState({
field1, field2, field3, field4, field5, field6
});

const handleNext = (newValues) => {
setFormValues({ ...formValues, ...newValues });
setActiveStep(activeStep + 1);
};

const handleBack = (newValues) => {
setFormValues({ ...formValues, ...newValues });
setActiveStep(activeStep - 1);
};

function getStepContent(step) {
const isLastStep = (activeStep === steps.length - 1);
switch (step) {
case 0:
return <BasicFormA {...formValues} activeStep={activeStep} isLastStep={isLastStep} handleBack={handleBack} handleNext={handleNext}/>;
case 1:
return <BasicFormB {...formValues} activeStep={activeStep} isLastStep={isLastStep} handleBack={handleBack} handleNext={handleNext}/>;
case 2:
return <BasicFormC {...formValues} activeStep={activeStep} isLastStep={isLastStep} handleBack={handleBack} handleNext={handleNext}/>;
default:
throw new Error('Mis-step!');
}
}

return (
<div className="MultiStepForm">
<Stepper activeStep={activeStep} className={classes.stepper}>
{steps.map(label => (
<Step key={label}>
<StepLabel>{label}</StepLabel>
</Step>
))}
</Stepper>
<Fragment>
{activeStep === steps.length ? (
<p>You're done!<p>
) : (
<Fragment> {getStepContent(activeStep)} <Fragment>
)}
<Fragment>
</div>
);
}

export default MultiStepForm;

此时,子表单可以在进入下一步之前检查其字段是否有效:

import React from 'react';

import {Formik, useField, Field, Form} from 'formik';
import { TextField } from 'formik-material-ui';
import * as Yup from "yup";
import { Button } from '@material-ui/core';

export default function BasicForm(props) {

const { values, field1, field2, activeStep, isLastStep, handleBack, handleNext } = props;

return (
<div>
<Formik
initialValues={{
field1,
field2
}}
validationSchema={Yup.object({
field1: Yup.string()
.required('Required'),
field2: Yup.string()
.required('Required'),
})}
>
{({submitForm, validateForm, setTouched, isSubmitting, values, setFieldValue}) => (
<Form>
<Field name="field1" type="text" label="Field 1" variant="outlined" margin="normal" fullWidth multiline component={TextField} />
<Field name="field2" type="text" label="Field 2" variant="outlined" margin="normal" fullWidth multiline component={TextField} />
</Form>
<div>
{activeStep !== 0 && (
<Button onClick={() => { handleBack(values) } } className={classes.button}> Back </Button>
)}
<Button className={classes.button} variant="contained" color="primary"
onClick={
() => validateForm()
.then((errors) => {
if(Object.entries(errors).length === 0 && errors.constructor === Object ) {
handleNext(values);
} else {
setTouched(errors);
}
})
} >
{isLastStep ? 'Submit Draft' : 'Next'}
</Button>
</div>
)}
</Formik>
</div>
);
}

唯一的其他技巧是在子表单无效时记住 setTouched(errors),以便显示未触及的字段的验证错误。

关于reactjs - 使用 React Hooks 跨 Material-UI Stepper 传递数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59035989/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com