I'm migrating ant-design to v4, and I'm not sure what is the remended way to migrate the following case.
I have a form, with an input, and a submit button. The submit button is not rendered unless form.isFieldsTouched() === true
. In v3 this was not a problem to implement.
Antd v4 is using hooks, and this became a problem.
Consider the following form. The submit button will not render after the input is changed. =/src/App.js
import { Form, Input } from "antd";
export default function App() {
const [form] = Form.useForm();
return (
<Form form={form}>
<Form.Item name="name">
<Input />
</Form.Item>
{form.isFieldsTouched() && <button type="submit">Submit</button>}
</Form>
);
}
There's a "way" to make it work and render, but it feels wrong and hacky. Also Form.Item
adds it's unwanted styles. =/src/App.js
import { useState } from 'react';
import { Form, Input } from "antd";
export default function App() {
const [form] = Form.useForm();
const [isTouched, setIsTouched] = useState(form.isFieldsTouched());
return (
<Form form={form}>
<Form.Item name="name">
<Input />
</Form.Item>
<Form.Item
shouldUpdate={() => {
const didChange = form.isFieldsTouched() !== isTouched;
if (didChange) {
setIsTouched(form.isFieldsTouched());
}
return didChange;
}}
>
{() => form.isFieldsTouched() && <button type="submit">Submit</button>}
</Form.Item>
</Form>
);
}
Did you have a similar case? How did you solve it?
I'm migrating ant-design to v4, and I'm not sure what is the remended way to migrate the following case.
I have a form, with an input, and a submit button. The submit button is not rendered unless form.isFieldsTouched() === true
. In v3 this was not a problem to implement.
Antd v4 is using hooks, and this became a problem.
Consider the following form. The submit button will not render after the input is changed. https://codesandbox.io/s/zealous-rgb-pc7ke?file=/src/App.js
import { Form, Input } from "antd";
export default function App() {
const [form] = Form.useForm();
return (
<Form form={form}>
<Form.Item name="name">
<Input />
</Form.Item>
{form.isFieldsTouched() && <button type="submit">Submit</button>}
</Form>
);
}
There's a "way" to make it work and render, but it feels wrong and hacky. Also Form.Item
adds it's unwanted styles. https://codesandbox.io/s/delicate-browser-0y9f9?file=/src/App.js
import { useState } from 'react';
import { Form, Input } from "antd";
export default function App() {
const [form] = Form.useForm();
const [isTouched, setIsTouched] = useState(form.isFieldsTouched());
return (
<Form form={form}>
<Form.Item name="name">
<Input />
</Form.Item>
<Form.Item
shouldUpdate={() => {
const didChange = form.isFieldsTouched() !== isTouched;
if (didChange) {
setIsTouched(form.isFieldsTouched());
}
return didChange;
}}
>
{() => form.isFieldsTouched() && <button type="submit">Submit</button>}
</Form.Item>
</Form>
);
}
Did you have a similar case? How did you solve it?
Share Improve this question asked May 7, 2021 at 10:39 Martin SkecMartin Skec 1282 silver badges9 bronze badges 3-
1
antd
usesrc-field-form
under the hood and the reason you need to resort to those kind of hacks is a poor API design of that library. It's supposed to improve render performance by bailing out from rendering everywhere but doesn't provide an API to subscribe to certain changes in form state. For me that is premature optimization as most forms don't need that degree of render performance. It does more harm than good. Just my opinion. I like to useformik
which allows you to opt-in into optimizations if you really need them. – trixn Commented May 7, 2021 at 12:28 -
@trixn thanks for the explanation. Now I realize there will be similar issues for other methods like
form.getFieldValue('some-field')
, and working around it with hacks like above can get very plex very fast. This is quite bad DX, and I will consider migrating to another form library. – Martin Skec Commented May 7, 2021 at 13:06 -
1
This is an issue related to your problem: github./react-ponent/field-form/issues/153. Form rendering is one of the harder things in react. I know of 3 popular form libraries for react:
formik
,react-final-form
andreact-hook-form
which all have their quirks. I don't know how well they would work together with antd ponents to be honest. There may be a more elegant solution usingrc-field-form
but from reading the docs there is no obvious way to deal with your specific problem in a better way as far as I can tell. – trixn Commented May 7, 2021 at 13:21
2 Answers
Reset to default 3I had the similar problem and at that time I solved it like this:
import { useState } from "react";
import { Form, Input } from "antd";
export default function App() {
const [form] = Form.useForm();
const [isTouched, setIsTouched] = useState();
return (
<Form
form={form}
onFieldsChange={() => {
// add your additionaly logic here
setIsTouched(true);
}}
>
<Form.Item name="name">
<Input />
</Form.Item>
<Form.Item>
{isTouched && <button type="submit">Submit</button>}
</Form.Item>
</Form>
);
}
I too had a similar problem. This worked for me.
import { useState } from 'react';
import { Form, Input } from "antd";
export default function App() {
const [form] = Form.useForm();
return (
<Form form={form}>
<Form.Item name="name">
<Input />
</Form.Item>
<Form.Item
shouldUpdate={true}
>
{() => form.isFieldsTouched() && <button type="submit">Submit</button>}
</Form.Item>
</Form>
);
}