清除嵌套字段的条件隐藏上的子窗体值



使用React+Formik,我想创建一个可重复使用的组件,我们可以使用它来有条件地显示/隐藏嵌套的子窗体(任何复杂度(。

每次它被隐藏时,我们都希望清除这些值,这样这些值就不会被提交。

下面显示了一个名为OptionalFeature的简单隐藏/显示组件。

const OptionalFeature = ({
toggle,
children
}) => {
if (toggle) {
return <div>{children}</div>
} else {
return null;
}
}

可以通过粘贴到https://codesandbox.io/s/zkrk5yldz但正如你在演示中看到的,让孩子们隐形并不能明确他们的价值观。理想情况下,每个子级都可以定义自己的clearValue行为(示例非常简单,我们希望有更复杂的嵌套表单(。

通过以通用、可重用的方式扩展OptionalFeature类来清除全名字段的干净解决方案是什么?

我已经尝试创建一个清理函数,并在if块内从OptionalFeature调用它,但它似乎不太习惯。

// Helper styles for demo
import "./helper.css";
import { DisplayFormikState } from "./helper";
import React from "react";
import { render } from "react-dom";
import { Formik } from "formik";
// Generic reusable component to show/hide sub-forms
const OptionalFeature = ({
toggle,
children
}) => {
if (toggle) {
return <div>{children}</div>
} else {
return null;
}
}
const App = () => (
<div className="app">
<Formik
initialValues={{ email: "", anonymous: false, fullname:"" }}
onSubmit={async values => {
await new Promise(resolve => setTimeout(resolve, 500));
alert(JSON.stringify(values, null, 2));
}}
>
{props => {
const {
values,
touched,
errors,
isSubmitting,
handleChange,
handleSubmit
} = props;
return (
<form onSubmit={handleSubmit}>
<input
id="email"
placeholder="Enter your email"
type="text"
value={values.email}
onChange={handleChange}
/>
{/* This checkbox should show/hide next field */}
<div style={{ display: "white-space:nowrap" }}>
<label htmlFor="anonymous" style={{ display: "inline-block"}}>Anonymous</label>
<input 
id="anonymous" 
type="checkbox" 
name="anonymous" 
value={values.anonymous}
onChange={handleChange}
style={{ display: "inline-block", width: "20%"}}
/>
</div>

<OptionalFeature
toggle={!values.anonymous}
>
{/* Imagine this subform comes from a different file */}
<input
id="fullname"
placeholder="Enter your full name"
type="text"
value={values.fullname}
onChange={handleChange}
/>
</OptionalFeature>

<button type="submit" disabled={isSubmitting}>
Submit
</button>
<DisplayFormikState {...props} />
</form>
);
}}
</Formik>
</div>
);
render(<App />, document.getElementById("root"));

这是我现有的方法,正在等待更好的答案:

const OptionalFeature = ({
toggle,
onHide,
children
}) => {
if (toggle) {
return <div>{children}</div>
} else {
// useEffect needed because onHide function could trigger anything.
// Also to avoid calling multiple times.
useEffect(() => {
onHide();
}, [toggle, onHide])
return null;
}
}

然后稍后调用Hide:上的清理函数

<Formik
initialValues={{ email: "", anonymous: false, fullname:"" }}
...>
{props => {
const {
values,
isSubmitting,
handleChange,
handleSubmit
} = props;
// to clean up all prop values inside the OptionalFeature
const clearFullName = () => 
{
values.fullname = ""
}
return (
//...

<OptionalFeature
toggle={!values.anonymous}
onHide={clearFullName}      // using cleanup Function
>
<input
id="fullname"
placeholder="Enter your full name"
type="text"
value={values.fullname}
onChange={handleChange}
/>
</OptionalFeature>
);
}}
</Formik>

我不喜欢的是,随着for变得越来越复杂,可选功能中嵌套了更多OptionalFeatures或更多元素,很难检查嵌套可选表单中的所有字段是否都被清除。此外,useEffect的特性似乎很难测试。

我更喜欢某种嵌套的子窗体,这样我就可以编写类似onHide={handleReset}的东西,并且这将只适用于嵌套子窗体中的字段,而不必为此定义自定义handleReseet函数。

最新更新