我有一個這樣的物件:
const initialValues = {
"Name": "",
"Price": "",
"Quantity": "",
"Details": {
"Light": "",
"Watering": "",
"Maintenance": "",
"WhereToGrow": "",
},
"BrowseImg": "",
"MainImg": "",
"Tags": "",
"Category": "Plant",
"SubCategory": ""
}
我在我的表單組件中使用 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>
現在,我需要在選擇initialValues時將物件更改"Planters"為:
{
"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;
};
當是 Planters 時更改名稱values.Category會引發 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.
我如何實作這一目標?提前致謝!
uj5u.com熱心網友回復:
這不是完全正確的方法,對我來說即時更改表單中的欄位集也不是一個好主意——你會遇到支持你自己的糾結代碼的問題,這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>
and in the same component two or more sets of fields. Each set is rendered according to SelectedCategory value. There's no need to change or reset values in sets of fields when SelectedCategory changes - you can remove or reset the fields on the stage of sending the data.
if (values.SelectedCategory === 'Planers') {
// render set of fields for Planers
}
if (values.SelectedCategory === 'Plants') {
// render set of fields for Plants
}
And onSubmit you can transform your filed values as you like:
<Formik
initialValues
onSubmit={(values, {resetForm}) => {
const transformedDataForAsyncRequest = yourCustomDataTransducer(values);
axios({
method: 'post',
data: transformedDataForAsyncRequest
})
.then(() => {resetForm()})
.catch((e) => {console.log(e)})
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/457165.html
標籤:javascript 反应 目的 形式 对
