如何解决使用 Formik 向导访问上一步中的值
我正在使用 Formik's Wizard component 创建一个多步骤表单。我不知道如何访问前一个 <WizardStep />
中的值。例如,在步骤 1 中有 firstName
和 lastName
的字段。是否可以在第二步中读取这些值?
所有值都在第二步 onSubmit
中打印,但如何在实际的 <WizardStep />
组件中访问它们?
基本上如何将 props 传递给下一个 <WizardStep />
import React,{ useState } from 'react';
import { ErrorMessage,Field,Form,Formik } from 'formik';
import * as Yup from 'yup';
import { Debug } from './Debug';
const sleep = ms => new Promise(resolve => setTimeout(resolve,ms));
// Wizard is a single Formik instance whose children are each page of the
// multi-step form. The form is submitted on each forward transition (can only
// progress with valid input),whereas a backwards step is allowed with
// incomplete data. A snapshot of form state is used as initialValues after each
// transition. Each page has an optional submit handler,and the top-level
// submit is called when the final page is submitted.
const Wizard = ({ children,initialValues,onSubmit }) => {
const [stepNumber,setStepNumber] = useState(0);
const steps = React.Children.toArray(children);
const [snapshot,setSnapshot] = useState(initialValues);
const step = steps[stepNumber];
const totalSteps = steps.length;
const isLastStep = stepNumber === totalSteps - 1;
const next = values => {
setSnapshot(values);
setStepNumber(Math.min(stepNumber + 1,totalSteps - 1));
};
const prevIoUs = values => {
setSnapshot(values);
setStepNumber(Math.max(stepNumber - 1,0));
};
const handleSubmit = async (values,bag) => {
if (step.props.onSubmit) {
await step.props.onSubmit(values,bag);
}
if (isLastStep) {
return onSubmit(values,bag);
} else {
bag.setTouched({});
next(values);
}
};
return (
<Formik
initialValues={snapshot}
onSubmit={handleSubmit}
validationSchema={step.props.validationSchema}
>
{formik => (
<Form>
<p>
Step {stepNumber + 1} of {totalSteps}
</p>
{step}
<div style={{ display: 'flex' }}>
{stepNumber > 0 && (
<button onClick={() => prevIoUs(formik.values)} type="button">
Back
</button>
)}
<div>
<button disabled={formik.isSubmitting} type="submit">
{isLastStep ? 'Submit' : 'Next'}
</button>
</div>
</div>
<Debug />
</Form>
)}
</Formik>
);
};
const WizardStep = ({ children }) => children;
const App = () => (
<div>
<h1>Formik Multistep Wizard</h1>
<Wizard
initialValues={{
email: '',firstName: '',lastName: '',}}
onSubmit={async values =>
sleep(300).then(() => console.log('Wizard submit',values))
}
>
<WizardStep
onSubmit={() => console.log('Step1 onSubmit')}
validationSchema={Yup.object({
firstName: Yup.string().required('required'),lastName: Yup.string().required('required'),})}
>
<div>
<label htmlFor="firstName">First Name</label>
<Field
autoComplete="given-name"
component="input"
id="firstName"
name="firstName"
placeholder="First Name"
type="text"
/>
<ErrorMessage className="error" component="div" name="firstName" />
</div>
<div>
<label htmlFor="lastName">Last Name</label>
<Field
autoComplete="family-name"
component="input"
id="lastName"
name="lastName"
placeholder="Last Name"
type="text"
/>
<ErrorMessage className="error" component="div" name="lastName" />
</div>
</WizardStep>
<WizardStep
onSubmit={() => console.log('Step2 onSubmit')}
validationSchema={Yup.object({
email: Yup.string()
.email('Invalid email address')
.required('required'),})}
>
<div>
<label htmlFor="email">Email</label>
<Field
autoComplete="email"
component="input"
id="email"
name="email"
placeholder="Email"
type="text"
/>
<ErrorMessage className="error" component="div" name="email" />
</div>
</WizardStep>
</Wizard>
</div>
);
export default App;
解决方法
您可以为此使用 React 上下文或 Redux。下面是如何使用 React Context 做到这一点。
第 1 步:创建一个“提供者”,它将成为所有向导步骤的状态容器。它非常简单,只包含一个状态。
const WizardContext = createContext();
const WizardProvider = ({ children }) => {
const [wizardState,setWizardState] = useState({});
const value = useMemo(() => [wizardState,setWizardState],[
wizardState,setWizardState
]);
return (
<WizardContext.Provider value={value}>{children}</WizardContext.Provider>
);
};
const useWizardContext = () => useContext(WizardContext);
第 2 步:修复您的 App
组件并将其内容包装在提供程序中:
const App = () => (
<div>
<h1>Formik Multistep Wizard</h1>
<WizardProvider>
<AppContainer />
</WizardProvider>
</div>
);
第 3 步:按以下方式使用向导上下文。基本上,通过 setWizardState
函数控制全局状态并通过 wizardState
访问它。
const AppContainer = () => {
const [wizardState,setWizardState] = useWizardContext();
return (
<Wizard .....>
<WizardStep onSubmit={(values) => {
setWizardState(values);
console.log("Step1 onSubmit");
}}></WizardStep>
<WizardStep onSubmit={() => {
console.log(wizardState);
console.log("Step2 onSubmit");
}}>
<div>{wizardState.firstName}</div>
</WizardStep>
</Wizard>
)
}
这是一个完整的代码沙盒示例:https://codesandbox.io/s/funny-galois-8xxwd?file=/src/App.js
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。