Und*_*ned 6 javascript forms reactjs next.js stepper
我正在使用 React 制作一个步进表单。表格结构也差不多完成了..
有两个步骤,
-> Basic Details
-> Employment Details
Run Code Online (Sandbox Code Playgroud)
这里,表单上下文用于填写输入字段的默认值,如果进行任何更改,则将通过状态存储。
表单上下文.js
import React, { useState } from 'react';
export const FormContext = React.createContext();
export function FormProvider({ children }) {
const [formValue, setFormValue] = useState({
basicDetails: {
firstName: 'John',
lastName: '',
},
companyDetails: {
companyName: 'Some Company',
designation: 'Some Designation',
},
});
return (
<FormContext.Provider value={[formValue, setFormValue]}>
{children}
</FormContext.Provider>
);
}
Run Code Online (Sandbox Code Playgroud)
这里我有下一个和上一个按钮可以在步骤之间移动,
索引.js:
const next = () => setCurrentPage((prev) => prev + 1);
const prev = () => setCurrentPage((prev) => prev - 1);
Run Code Online (Sandbox Code Playgroud)
要求:
-> 单击next/previous按钮时,我需要检查是否有任何输入发生更改。
-> 通过这个我可以调用 API 来保存在我的实际应用程序中单击下一步按钮时的更改。
-> 在这里,如果你帮我做一些console log那就足够了。
例如:
-> 如果用户将基本详细信息部分中的名字从 修改为 ,John则Doe单击下一步按钮可以控制台记录基本详细信息发生更改。
-> 如果基本详细信息部分中的任何字段均未更改,则可以直接继续下一步(就像现在一样)。
注意:请不要硬编码任何输入名称,因为每个步骤都有 30 多个输入字段。
我认为这里的主要问题是您当前的实现在每次更改时都会替换现有状态,因此不可能知道是否更改/更改了什么。即使是保存先前状态值的“usePrevious”钩子在这里也不起作用,因为它只能保存最后一次字段编辑,而不是原始值,以进行比较。许多表单处理解决方案通过保持未变异的初始状态或跟踪“脏”字段等来处理此问题。
这是我的建议,调整表单上下文状态以跟踪已更新的字段。该dirtyFields对象保留原始值。
表单提供者
const [formValue, setFormValue] = useState({
basicDetails: {
fields: {
firstName: 'John',
lastName: '',
},
dirtyFields: {},
},
companyDetails: {
fields: {
companyName: 'Some Company',
designation: 'Some Designation',
},
dirtyFields: {},
},
});
Run Code Online (Sandbox Code Playgroud)
基本详情
const BasicDetails = () => {
const [value, setValue] = React.useContext(FormContext);
const {
basicDetails: { fields }, // <-- get field values
} = value;
const handleInputChange = (event) => {
const { name, value } = event.target;
setValue((prev) => ({
...prev,
basicDetails: {
...prev.basicDetails,
fields: {
...prev.basicDetails.fields,
[name]: value,
},
...(prev.basicDetails.dirtyFields[name] // <-- only mark dirty once with original value
? {}
: {
dirtyFields: {
...prev.basicDetails.dirtyFields,
[name]: prev.basicDetails.fields[name],
},
}),
},
}));
};
return (
<>
<div className="form-group col-sm-6">
<label htmlFor="firstName">First Name</label>
<input
...
value={fields.firstName} // <-- access fields object
...
/>
</div>
<div className="form-group col-sm-4">
<label htmlFor="lastName">Last Name</label>
<input
...
value={fields.lastName}
...
/>
</div>
</>
);
};
Run Code Online (Sandbox Code Playgroud)
就业详情
const EmploymentDetails = () => {
const [value, setValue] = React.useContext(FormContext);
const {
companyDetails: { fields },
} = value;
const handleInputChange = (event) => {
const { name, value } = event.target;
setValue((prev) => ({
...prev,
companyDetails: {
...prev.companyDetails,
fields: {
...prev.companyDetails.fields,
[name]: value,
},
...(prev.companyDetails.dirtyFields[name]
? {}
: {
dirtyFields: {
...prev.companyDetails.dirtyFields,
[name]: prev.companyDetails.fields[name],
},
}),
},
}));
};
return (
<>
<div className="form-group col-sm-6">
<label htmlFor="companyName">Company Name</label>
<input
...
value={fields.companyName}
...
/>
</div>
<div className="form-group col-sm-4">
<label htmlFor="designation">Designation</label>
<input
...
value={fields.designation}
...
/>
</div>
</>
);
};
Run Code Online (Sandbox Code Playgroud)
递增/递减步骤时检查脏字段。
为每个部分提供一个与表单上下文中的“表单键”相匹配的 id。
const sections = [
{
title: 'Basic Details',
id: 'basicDetails',
onClick: () => setCurrentPage(1),
},
{
title: 'Employment Details',
id: 'companyDetails',
onClick: () => setCurrentPage(2),
},
{ title: 'Review', id: 'review', onClick: () => setCurrentPage(3) },
];
Run Code Online (Sandbox Code Playgroud)
创建一个checkDirty实用程序。这里我简单记录一下脏字段
const checkDirty = (page) => {
console.log('check dirty', 'page', page);
console.log(
value[sections[page - 1].id] && value[sections[page - 1].id].dirtyFields,
);
};
const next = () => {
setCurrentPage((prev) => prev + 1);
checkDirty(currentPage); // <-- check for dirty fields when updating page step
};
const prev = () => {
setCurrentPage((prev) => prev - 1);
checkDirty(currentPage);
};
Run Code Online (Sandbox Code Playgroud)
由于表单上下文中存在额外的嵌套状态,这里有一个实用程序可将其还原为您想要在审阅步骤中呈现的表单数据。
const prettyReview = sections.reduce(
(sections, section) => ({
...sections,
...(value[section.id]
? { [section.id]: { ...value[section.id].fields } }
: {}),
}),
{},
);
...
<pre>{JSON.stringify(prettyReview, null, 2)}</pre>
Run Code Online (Sandbox Code Playgroud)
您说您的数据来自后端 API 调用。这是一个上下文状态初始化函数,它将 API 数据形状映射到我拥有的状态形状。
给定来自 API 的数据
const apiData = {
basicDetails: {
firstName: 'John',
lastName: '',
},
companyDetails: {
companyName: 'Some Company',
designation: 'Some Designation',
},
};
Run Code Online (Sandbox Code Playgroud)
初始化函数
const initializeContext = (data) =>
Object.entries(data).reduce(
(sections, [section, fields]) => ({
...sections,
[section]: {
fields,
dirtyFields: {},
},
}),
{},
);
Run Code Online (Sandbox Code Playgroud)
初始化FormProvider上下文状态
function FormProvider({ children }) {
const [formValue, setFormValue] = useState(initializeContext(apiData));
return (
<FormContext.Provider value={[formValue, setFormValue]}>
{children}
</FormContext.Provider>
);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
11116 次 |
| 最近记录: |