如何根据ReactJS中的选择更改Form initialValues和字段



我有一个这样的对象:

const initialValues = {
"Name": "",
"Price": "",
"Quantity": "",
"Details": {
"Light": "",
"Watering": "",
"Maintenance": "",
"WhereToGrow": "",
},
"BrowseImg": "",
"MainImg": "",
"Tags": "",
"Category": "Plant",
"SubCategory": ""
}

我在我的Form Component中使用React Formik库,我正在渲染selection&Details object像这样:


<Grid item xs={6}>
<FormControl required>
<InputLabel id="demo-simple-select-required-label">Category</InputLabel>
<Select
labelId="demo-simple-select-required-label"
id="demo-simple-select-required"
value={values.Category !== "undefined" ? values.Category : ""}
label="Category *"
onChange={(e) => {
setFieldValue("Category", e.target.value);
}}
autoWidth
name="Category"
defaultValue=""
>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={"Plant"}>Plant</MenuItem>
<MenuItem value={"Planters"}>Planters</MenuItem>
<MenuItem value={"Seeds"}>Seeds</MenuItem>
</Select>
</FormControl>
</Grid>
<FieldArray name="Details">
<Grid container spacing={2} sx={{ padding: "20px" }}>
<Grid item xs={12}>
<Typography>Details</Typography>
</Grid>
<Grid item xs={6}>
<TextFieldWrapper
name={
values.Category !== "Planters"
? `Details.Light`
: `Details.Material`
}
label={values.Category !== "Planters" ? `Light` : "Material"}
/>
</Grid>
<Grid item xs={6}>
<TextFieldWrapper
name={
values.Category !== "Planters"
? `Details.Watering`
: `Details.Build`
}
label={values.Category !== "Planters" ? `Watering` : "Build"}
/>
</Grid>
<Grid item xs={6}>
<TextFieldWrapper
name={
values.Category !== "Planters"
? `Details.Maintenance`
: `Details.PlanterHeight`
}
label={
values.Category !== "Planters" ? `Maintenance` : "Planter Height"
}
/>
</Grid>
<Grid item xs={6}>
<TextFieldWrapper
name={
values.Category !== "Planters"
? `Details.WhereToGrow`
: `Details.PlanterWidth`
}
label={
values.Category !== "Planters" ? `Where To Grow` : "Planter Width"
}
/>
</Grid>
</Grid>
</FieldArray>

现在,当选择"Planters"时,我需要将initialValues对象更改为:

{
"Name": "",
"Price": "",
"Quantity": "",
"Details": {
"Material": "",
"Build": "",
"PlanterHeight": "",
"PlanterWidth": ""
},
"BrowseImg": "",
"MainImg": "",
"Tags": "",
"Category": "Planters",
"SubCategory": ""
}

我尝试这样更改initialValues对象中的密钥名称,如下所示:

const Context = () => {
const { values } = useFormikContext();
useEffect(() => {
if (values.Category === "Planters") {
delete Object.assign(initialValues.Details, {
Material: initialValues.Details.Light,
})["Light"];
delete Object.assign(initialValues.Details, {
Build: initialValues.Details.Watering,
})["Watering"];
delete Object.assign(initialValues.Details, {
PlanterHeight: initialValues.Details.Maintenance,
})["Maintenance"];
delete Object.assign(initialValues.Details, {
PlanterWidth: initialValues.Details.WhereToGrow,
})["WhereToGrow"];
console.log("VALUES FORMIK CONTEXT", values);
console.log("INITIALVALUES", initialValues);
console.log(
"INITIAL VALUES DETAILS ",
initialValues.Details.Material
);
}
}, [values]);
return null;
};

values.Category为Planters时更改名称会引发Formik错误,如下所示:

Warning: A component is changing a controlled input to be uncontrolled. This is likely caused by the value changing from a defined to undefined, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component.

我该如何做到这一点?提前感谢!

这不是一种非常正确的方法,对我来说,动态更改表单中的字段集也不是一个好主意——你会在支持自己的复杂代码时遇到问题,这个useEffect完全是一团糟。

请记住,用于UI的表单数据可能与发送到后端的数据不同,并且可以在发出请求之前进行转换。实际上initialValues是用于初始化表单的,不应该从表单内部更改。我会创建一组通用的字段。

例如,我会更改数据的初始数据,如

// read-only array to render Select, add as much item as you like.
// In general, since it's just an array for options,
// it can be safely extracted to external constant
// and may not present in initialData. 
Categories: [
{
name 'Planers',
selected: true,
},
{
name: 'Plants'
} 
],
SelectedCategory: 'Planers', // since selected is true 
Planters: {
"Material": "",
"Build": "",
"PlanterHeight": "",
"PlanterWidth": ""
},
Plants: {
"Light": "",
"Watering": "",
"Maintenance": "",
"WhereToGrow": "",
}

然后以你的形式

// ...
const { values, handleChange, handleBlur } = useFormikContext();
<Select
onChange={handleChange} // or your own handler
onBlur={handleBlur}
name="SelectedCategory"
>
{values.Categories.map(({name, selected}) => (
<MenuItem
key={name}
selected={selected}
>
{name}
</MenuItem >
))}
</Select>

并且在同一组件中有两组或更多组字段。每个集合都根据SelectedCategory值进行渲染。SelectedCategory更改时,无需更改或重置字段集中的值-您可以在发送数据的阶段删除或重置字段。

if (values.SelectedCategory === 'Planers') {
// render set of fields for Planers
}
if (values.SelectedCategory === 'Plants') {
// render set of fields for Plants
}

onSubmit您可以随心所欲地转换您的归档值:

<Formik
initialValues
onSubmit={(values, {resetForm}) => {
const transformedDataForAsyncRequest = yourCustomDataTransducer(values);
axios({
method: 'post',
data: transformedDataForAsyncRequest
})
.then(() => {resetForm()})
.catch((e) => {console.log(e)})
}
}

最新更新