React-hook-form for antd
so in this link https://refine.dev/docs/packages/react-hook-form/introduction/ it describes react-hook-form implementation for headless/materialui/chakraui. how about antd?
Introduction | Refine
Refine provides an integration package for React Hook Form library. This package enables you to manage your forms in a headless manner. This adapter supports all of the features of both React Hook Form and Refine's useForm hook. Simply, you can use any of the React Hook Form examples as-is by copying and pasting them into your project.
32 Replies
Hi @biohazard#1521. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
----------------------
For Ant Design, Refine provides its own specialized
useForm
hook directly from the @refinedev/antd
package rather than using the React Hook Form integration. This is because Ant Design has its own form handling system that Refine integrates with natively.
The @refinedev/antd
package includes a useForm
hook that is specifically designed to work with Ant Design's <Form />
component. This hook extends Refine's core useForm
hook with additional features tailored for Ant Design forms.
Here's a basic example of how to use the Ant Design form integration:
You can find more detailed information about using forms with Ant Design in Refine in the following resources:
- Ant Design Form Integration Documentation
- Form Examples with Ant Design
Refine also provides additional form-related hooks for Ant Design such as:
- useDrawerForm
for forms in drawers
- useModalForm
for forms in modals
- useStepsForm
for multi-step forms
These specialized hooks make it easier to implement different types of form patterns in your Refine applications with Ant Design.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@680514070167683118> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
stormy-goldOP•3w ago
@kapa.ai the problem with useForm from antd, i can't find a way to validate the form using zod schema for example
Let me check the knowledge base for you again. One moment! :books:
----------------------
Based on the knowledge sources provided, there isn't specific information about using Zod schema validation with Refine's Ant Design
useForm
hook. The documentation primarily shows validation using Ant Design's built-in validation system through the rules
property of Form.Item
.
For custom validations with Ant Design forms in Refine, the documentation mentions using the validator function within the Form.Item
rules property:
If you're looking for schema-based validation similar to Zod, you might want to check out the Custom Form Validation example which demonstrates more advanced validation techniques with Ant Design forms.
For React Hook Form with Zod integration, Refine does provide support through @refinedev/react-hook-form
, but as we discussed earlier, this is primarily for headless, Material UI, and Chakra UI implementations rather than Ant Design.
If you need schema validation with Ant Design forms, you might need to implement a custom solution that combines Ant Design's form validation system with Zod schema validation in your form submission logic.
Would you like me to explore any specific aspect of form validation with Refine's Ant Design integration in more detail?
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@680514070167683118> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
stormy-goldOP•3w ago
@kapa.ai the problem is that i don't want to use the antd validation because it is ugly and needs to be implemented per field. i want to work with zod/yup schema
Let me check the knowledge base for you again. One moment! :books:
----------------------
I understand your preference for using schema-based validation with Zod or Yup instead of Ant Design's field-by-field validation approach.
Based on the knowledge sources, there is a way to use schema validation with Refine forms, but the examples primarily show this with React Hook Form rather than directly with Ant Design's form system.
For schema validation with Yup, there's an example in the React Hook Form integration:
For Zod validation, there's a Discord thread that mentions using Zod with
useStepsForm
:
However, there appears to be a bug with useStepsForm
and Zod validation as mentioned in the Discord thread, where it tries to validate fields that haven't been shown yet in multi-step forms.
For server-side validation, Refine's Ant Design integration does support handling validation errors returned from the server. When the dataProvider
returns a rejected promise with an errors
field, the form will automatically update with those errors.
If you're determined to use schema validation with Ant Design forms, you might need to:
1. Use the React Hook Form integration with Refine and manually connect it to Ant Design components
2. Create a custom implementation that uses Zod/Yup for validation but still works with Ant Design's form components
Unfortunately, the knowledge sources don't provide a direct example of using Zod/Yup schema validation with Refine's Ant Design form integration.
Would you like me to explore any specific aspect of these approaches in more detail?
React Hook Form Validation with Complete Examples provides more information about schema validation with Yup.
Discord support thread shows an example of using Zod with useStepsForm
.
Server-Side Form Validation demonstrates handling validation errors from the server.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@680514070167683118> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
stormy-goldOP•3w ago
@kapa.ai ok so i tried the headless way
import { HttpError } from '@refinedev/core';
import { useForm } from '@refinedev/react-hook-form';
import { Input } from 'antd';
export const ProposalEdit = () => {
const {
refineCore: { onFinish, formLoading, queryResult },
register,
handleSubmit,
formState: { errors, ...rest },
} = useForm<IPost, HttpError>({
refineCoreProps: {
resource: 'proposal',
action: 'edit',
// id: 1,
},
});
console.log('REST - ', register('name', { required: true }), queryResult);
return (
<form onSubmit={handleSubmit(onFinish)}>
<label>Name: </label>
<Input {...register('name', { required: true })} />
<input {...register('name', { required: true })} />
{errors.title && <span>This field is required</span>}
<br />
<label>Status: </label>
<select {...register('status')}>
<option value="published">published</option>
<option value="draft">draft</option>
<option value="rejected">rejected</option>
</select>
<br />
<label>Content: </label>
<textarea
{...register('content', { required: true })}
rows={10}
cols={50}
/>
{errors.content && <span>This field is required</span>}
<br />
<input type="submit" value="Submit" />
{formLoading && <p>Loading</p>}
</form>
);
};
export type IStatus = 'published' | 'draft' | 'rejected';
interface IPost {
id: number;
title: string;
content: string;
status: IStatus;
}
but the
name
field doesn't get filled even though the query should have it
it exists in queryResult.data.name
Let me check the knowledge base for you again. One moment! :books:
----------------------
I see the issue with your form not populating the default values from the query result. Based on the knowledge sources, there are a few ways to handle this when using
@refinedev/react-hook-form
.
The problem is that even though your data is being fetched correctly (as you can see in queryResult.data.name
), it's not automatically being set as the default value for your form fields.
Here are a few approaches to fix this:
1. Use the defaultValues
function
You can use an async defaultValues
function to fetch and set the initial values:
2. Use React's useEffect to update form values
Another approach is to use useEffect
to set the form values when the query data is loaded:
3. Use FormProvider with defaultValues
As shown in one of the Discord support threads:
The issue might also be related to the timing of when the data is loaded versus when the form is initialized. Make sure you're handling the loading state properly and only rendering the form when data is available.
Also, check if you're providing the correct ID for the record you want to edit. In your code, you've commented out the id
property in refineCoreProps
, which might be why the correct record isn't being fetched.
React Hook Form Introduction provides more information about using React Hook Form with Refine.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@680514070167683118> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
stormy-goldOP•3w ago
@kapa.ai what is this nonsense, i am sure that the query fetches correctly, so the hook form doesn't have any sort of integration for initialization of an edit form? it should be basic
Let me check the knowledge base for you again. One moment! :books:
----------------------
I understand your frustration. You're right that initializing form values for an edit form should be straightforward. Based on the knowledge sources, there is indeed built-in functionality in
useForm
from @refinedev/react-hook-form
to handle this, but there might be some issues with how it's working in your case.
According to the documentation, when using useForm
with action: "edit"
, it should automatically fetch the record data and populate the form fields. Let me explain what might be happening:
1. From the Discord support thread, there was a similar issue where default values weren't being populated. The support staff identified that:
"The field fetched by2. Another issue could be related to how your data provider is returning data. One user in the Discord thread found that their backend was returning "array of one object" instead of a single object, which was causing issues:useForm
must beundefined
fordefaultFormValues
to take effect. What I mean is, if the data from the backend is an empty string (content: ""
), it is still considered a value, sodefaultFormValues
won't apply."
"In my custom getOne function my backend is giving array of one object. For edit to work getOne must pass the object!!"3. There's also a potential issue with the timing of when data is loaded versus when the form is initialized. Here's what you can try: This approach uses the
reset
function from React Hook Form to set all form values once the data is loaded.
If you're still having issues, you might want to check:
1. The exact structure of your queryResult.data
2. Whether your field names in the form match exactly with the property names in your data
3. If there are any transformations happening in your data provider
React Hook Form Usage documentation shows that the edit functionality should work automatically when properly configured.
I hope this helps resolve your issue!
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@680514070167683118> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
stormy-goldOP•3w ago
@kapa.ai so my getOne method just returns data object. basically in queryResult i see data object which holds all the relevant values, including name. why wouldn't it initialize then?
Let me check the knowledge base for you again. One moment! :books:
----------------------
Based on the knowledge sources, there are several reasons why your form fields might not be initializing with the data from your
getOne
method, even though you can see the data in queryResult
.
From the GitHub issues and Discord support threads, there appears to be a known issue with form initialization in edit mode. Here are the most likely causes:
1. Race condition between data fetching and form initialization:
According to a GitHub issue: "When action
is 'edit' or 'clone' a race condition with async defaultFormValues
may occur. In this case, the form values will be the result of the last completed operation." Default Form Values Documentation
2. Form initialization timing:
The form might be initializing before the data is fetched. As mentioned in a GitHub issue: "We've set the default values of the form fields by adding the defaultValues
config to useForm()
's configuration argument object" React Hook Form Blog
3. Integration between useForm
and data fetching:
From a GitHub issue about this exact problem: "When using { queryResult } = useShow()
and passing queryResult to use(Modal)Form
with defaultFormValues, often yields empty defaultFormValues." GitHub Issue #1263
To fix this issue, you could try:
1. Use the setId
function that comes from useForm
:
This approach was suggested in a GitHub issue as a solution: "In fact, all you have to do is call the 'setId' function, which returns from the useForm hook, with the id of the record you want to edit." GitHub Issue #1729
2. Alternatively, you could disable the automatic fetching and set the values manually:
This approach was suggested in a Discord support thread: "you can set disable useForm fetching with queryOptions.enabled: false
and you can use defaultValues
"
The issue seems to be a known limitation with how the form initialization works with edit mode in Refine, particularly with the timing of when data is fetched versus when the form is initialized.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@680514070167683118> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
stormy-goldOP•3w ago
@kapa.ai i even added logs
const {
refineCore: { onFinish, formLoading, queryResult },
register,
handleSubmit,
formState: { errors, ...rest },
} = useForm<IPost, HttpError>({
refineCoreProps: {
resource: 'proposal',
action: 'edit',
// id: 1,
queryOptions: {
onSuccess: (data) => {
console.log('DATA - ', data);
},
onError: (error) => {
console.log('ERROR - ', error);
},
},
},
});
and i see the data log properly with just the object in question.
how can we log the form values to try and monitor if anything happens on initialization?
Let me check the knowledge base for you again. One moment! :books:
----------------------
Based on the knowledge sources, you can monitor form values in React Hook Form using the
watch()
method. This will help you see what's happening with your form values during initialization and as they change.
Here's how you can implement it:
As mentioned in the React Hook Form documentation:
"We can subscribe to form data using theThis will help you monitor what's happening with your form values and see if they're being properly initialized from your query data. You can also add awatch()
API. The entire formdata
object can be watched. Or individual fields of interest can also be watched. Watching form fields with thewatch()
API triggers re-renders, as it happens with pure controlled fields." Watching Form Fields in React Hook Form withwatch()
useEffect
to see when the form values change:
This should help you debug what's happening with your form initialization and see if the values from your query are being properly set in the form.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@680514070167683118> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
stormy-goldOP•3w ago
@kapa.ai i get name undefined constantly, so i presume no initialization happens. what are we missing here? it should work out of the box so what can be wrong?
Let me check the knowledge base for you again. One moment! :books:
----------------------
Based on the knowledge sources and our conversation, there are several potential issues that could be preventing the form initialization in your edit form. Let's explore what might be wrong:
1. Missing ID parameter:
I notice in your code that you've commented out the
id
parameter in refineCoreProps
. This is crucial for edit forms:
According to GitHub Issue #1729, you need to either:
- Provide the id
directly in the refineCoreProps
- Use the setId
function returned from useForm
2. Data structure mismatch:
The data returned by your getOne
method might not be in the structure that Refine expects. Check if your data is nested under a data
property (like queryResult.data.data.name
instead of queryResult.data.name
).
3. Form field name mismatch:
Ensure that the field names in your form match exactly with the property names in your data object.
4. Race condition:
There's a known race condition issue with useForm
in edit mode, as mentioned in GitHub Issue #4422. The form might be initializing before the data is fetched.
Here's what you can try:
Another approach from the Discord support thread suggests disabling the automatic query and using async defaultValues:
The issue might also be related to how your data provider is structured. Make sure it returns data in the format that Refine expects for the getOne
endpoint.
Let me know if any of these approaches help or if you need further assistance!
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@680514070167683118> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
stormy-goldOP•3w ago
@kapa.ai tried setting id. queryResult.data.name is already available.
name
field should be a matching then
or should it be queryResult.data.data.name?Let me check the knowledge base for you again. One moment! :books:
----------------------
Based on the knowledge sources, the structure of the data returned by
useForm
in edit mode depends on how your data provider is structured. Let's clarify the correct data path:
When using useForm
from @refinedev/react-hook-form
in edit mode, the query result typically has this structure:
So the correct path to access your field would be queryResult.data.data.name
, not just queryResult.data.name
.
This is because Refine's data providers typically wrap the actual record in a data
property inside the response object. This is mentioned in several examples in the documentation, such as:
Forms Basic Usage shows this pattern in their examples.
To fix your issue, try accessing the data with:
Or if you're logging the data:
If your data structure is different, you might need to adjust your data provider to match Refine's expected format, or modify how you access the data in your component.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@680514070167683118> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
stormy-goldOP•3w ago
@kapa.ai so once i switched to queryResult.data.data, it started working wiuth this approach:
import { HttpError } from '@refinedev/core';
import { useForm } from '@refinedev/react-hook-form';
import { Input } from 'antd';
import { useEffect } from 'react';
export const ProposalEdit = () => {
const {
refineCore: { onFinish, formLoading, queryResult },
register,
handleSubmit,
setValue,
watch,
setId,
formState: { errors },
} = useForm<IPost, HttpError>({
refineCoreProps: {
resource: 'proposal',
action: 'edit',
// Explicitly set the ID here if you have it
// id: 'ad14317b-a8af-444c-8e7c-817d2c830659',
},
});
// Log the current form values
console.log('Form values:', watch());
// Log the query result
console.log('Query result:', queryResult?.data);
// Use useEffect to manually set form values when data is loaded
useEffect(() => {
if (queryResult?.data?.data) {
console.log(
'Setting form values from query data:',
queryResult.data.data,
);
// Assuming your data structure is queryResult.data.data
setValue('name', queryResult.data.data.name);
// Set other fields as needed
}
}, [queryResult?.data?.data, setValue]);
return (
<form onSubmit={handleSubmit(onFinish)}>
<label>Name: </label>
<Input {...register('name', { required: true })} />
<input {...register('name', { required: true })} />
{errors.title && <span>This field is required</span>}
<br />
however the field was only prefilled on the htmlinput, but not antd input. why? also we still needed the useEffect hook
Let me check the knowledge base for you again. One moment! :books:
----------------------
I can see you've made progress by accessing the correct data path (
queryResult.data.data
), but you're still facing two issues:
1. The Ant Design <Input />
component isn't being populated while the HTML <input />
is
2. You still need to use the useEffect
hook to manually set values
Why Ant Design Input Isn't Being Populated
The issue with Ant Design's <Input />
component not being populated is related to how React Hook Form integrates with Ant Design components. When using register()
with Ant Design components, there's a compatibility issue because Ant Design components expect props in a different format than what register()
provides.
For Ant Design components, you need to use the Controller
component from React Hook Form:
Don't forget to destructure control
from useForm
:
Why You Still Need useEffect
You still need the useEffect
hook because of how the form initialization works in Refine with React Hook Form. The form doesn't automatically populate fields from the query result in edit mode without manual intervention.
This is a known limitation mentioned in several GitHub issues, including #1729 where users reported similar problems with form initialization in edit mode.
The useEffect
approach you're using is the recommended workaround:
Alternative Approach
If you want to avoid using useEffect
, you could try using the defaultValues
function with async:
This approach might help avoid the need for the useEffect
, but it's still addressing the same underlying issue with form initialization in edit mode.
The need for these workarounds suggests there might be room for improvement in how Refine handles form initialization in edit mode with React Hook Form, especially when integrating with UI libraries like Ant Design.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@680514070167683118> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
stormy-goldOP•3w ago
@kapa.ai the defaultValues approach seems better, but how come it doesn't do this under the hood? seems like such an oversight
Let me check the knowledge base for you again. One moment! :books:
----------------------
I understand your frustration. Based on the knowledge sources, there does seem to be a gap in how the
useForm
hook handles initialization in edit mode, particularly with React Hook Form integration.
The issue appears to be related to race conditions between different data fetching methods. According to the documentation:
"WhenThis race condition happens because: 1. When you setaction
is 'edit' or 'clone' a race condition withasync defaultFormValues
may occur. In this case, the form values will be the result of the last completed operation." Default Form Values Documentation
action: "edit"
, Refine automatically fetches data using its internal data provider
2. If you also provide defaultFormValues
as an async function, both operations run concurrently
3. Whichever completes last will determine the final form values
There have been several GitHub issues and Discord support threads about this problem. In one GitHub issue (#5727), a developer reported that defaultFormValues
wasn't working with useDrawerForm
, and the Refine team acknowledged this as a bug that needed fixing.
In another Discord thread, a support staff member explained:
"I found the issue,The recommended workaround from the support team is to disable the automatic fetching and use your ownasync defaultValues
doesn't work as expected whenaction: "edit"
but it works whenaction: "create"
. But it's kinda complicated task, because whenaction: "edit"
, useForm fetches data from the API and populates the form based on that data. Whichever returns later, overwrites the current data."
defaultValues
function:
It does seem like an oversight in the API design that could be improved to make the developer experience more seamless, especially for such a common use case as editing existing records.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@680514070167683118> Kapa.ai is still learning and improving, please let me know how I did by reacting below.