Next.js多步骤表单使用React Context修改Stepper步骤状态问题
核心问题说明
- 你的FormContext仅提供了steps状态的读取权限,没有对外暴露修改steps的方法,外部无法更新步进器状态
- index.js中重复定义了
formStep和activeStep两个功能完全一致的状态,没有和Context中的steps做联动 - index.js中没有引入FormContext,直接操作step变量自然会报未定义错误
修改方案
步骤1:更新Context文件,新增steps状态修改方法
在FormProvider中新增专门的状态更新方法,根据传入的激活步骤索引批量更新所有step的status,再将该方法暴露到Context中:
// context/FormContext.js import { useState, createContext, useContext } from "react"; export const FormContext = createContext(); export default function FormProvider({ children }) { const [data, setData] = useState({}); const [steps, setSteps] = useState([ { name: 'Vertrag', status: 'current' }, { name: 'Dateneingabe', status: 'upcoming' }, { name: 'Bestätigung', status: 'upcoming' }, ]); const setFormValues = (values) => { setData((prevValues) => ({ ...prevValues, ...values, })); }; // 新增:根据当前激活索引更新所有步骤的status const updateStepsStatus = (activeIndex) => { const newSteps = steps.map((step, idx) => { if (idx < activeIndex) return { ...step, status: 'complete' } if (idx === activeIndex) return { ...step, status: 'current' } return { ...step, status: 'upcoming' } }) setSteps(newSteps) } return ( <FormContext.Provider value={{ steps, data, setFormValues, updateStepsStatus }}> {children} </FormContext.Provider> ); } export const useFormData = () => useContext(FormContext);
步骤2:修改index.js,联动步骤切换逻辑
删掉重复的activeStep状态,直接用formStep作为激活索引,每次切换步骤时调用Context中的更新方法同步步进器状态:
// pages/index.js import { useState } from "react"; import Head from "next/head"; import Stepper from '../components/Stepper' import styles from "../styles/styles.module.scss"; import FormCard from "../components/FormCard"; import Navbar from "../components/Navbar"; import { useFormData } from "../context/FormContext"; // 引入Context Hook import { PersonalInfo, ConfirmPurchase, ContractInfo, } from "../components/Forms"; import FormCompleted from "../components/FormCompleted"; function classNames(...classes) { return classes.filter(Boolean).join(' ') } const App = () => { const { updateStepsStatus } = useFormData(); // 拿到步进器更新方法 const [formStep, setFormStep] = useState(0); const nextFormStep = () => { const newStep = formStep + 1 setFormStep(newStep); updateStepsStatus(newStep); // 切换步骤时同步更新步进器状态 }; const prevFormStep = () => { const newStep = formStep - 1 setFormStep(newStep); updateStepsStatus(newStep); // 切换步骤时同步更新步进器状态 }; return ( <div> <Head> <title>Next.js Multi Step Form</title> </Head> <Navbar /> <Stepper /> {/* 删掉多余的activeStep传参 */} <div className={styles.container}> <FormCard currentStep={formStep} prevFormStep={prevFormStep}> {formStep >= 0 && ( <ContractInfo formStep={formStep} nextFormStep={nextFormStep} /> )} {formStep >= 1 && ( <PersonalInfo formStep={formStep} nextFormStep={nextFormStep} /> )} {formStep >= 2 && ( <ConfirmPurchase formStep={formStep} nextFormStep={nextFormStep} /> )} {formStep > 2 && <FormCompleted />} </FormCard> </div> <div className="mt-1 mb-5 sm:mt-8 sm:flex sm:justify-center lg:justify-center"> <div className="rounded-md shadow"> <a role="button" tabIndex={0} onClick={prevFormStep} className="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base font-medium rounded-md text-white bg-yellow-500 hover:bg-yallow-600 md:py-4 md:text-lg md:px-10" > Back </a> </div> <div className="mt-3 sm:mt-0 sm:ml-3"> <a onClick={nextFormStep} className="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base font-medium rounded-md text-white bg-yellow-500 hover:bg-yallow-600 md:py-4 md:text-lg md:px-10" > Next </a> </div> </div> </div> ); }; export default App;
步骤3:确认全局包裹FormProvider
确保你的项目根组件(一般是pages/_app.js)已经用FormProvider包裹了所有页面组件,这样Context才能正常工作:
// pages/_app.js import FormProvider from '../context/FormContext' export default function MyApp({ Component, pageProps }) { return ( <FormProvider> <Component {...pageProps} /> </FormProvider> ) }
你现有的Stepper组件逻辑不需要修改,Context中的steps更新后会自动触发Stepper重新渲染,样式会同步更新。
内容的提问来源于stack exchange,提问作者Katharina Schreiber
相关产品推荐
相关产品推荐

