You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'm using react-hook-form 7.49.2 and ran into an issue where formState.isDirty doesn't seem to reflect the user's changes immediately after a reset() call — at least not on the first try.
What I'm doing:
I'm using reset({ ...data }) to populate the form from an external source (e.g., editing an item).
After that, the user modifies one of the fields.
Then I call formState.isDirty during form submission to check if the form was changed.
But formState.isDirty is always false on the first submission, even if a field was changed. If I try again (with or without changes), isDirty starts working correctly.
That reliably detects field changes, even after reset().
Am I doing something wrong?
Is this expected behavior for isDirty? Or should it reflect changes right after a user modifies the form post-reset?
I assumed isDirty should become true as soon as any field changes from its reset/default value, but maybe there's something I'm missing about how it's tracked internally.
I hope someone can clarify this for me. Thanks!
Code
import{Controller,useForm}from'react-hook-form';
...
constTypeSpecificSettings: React.FC=()=>{const{ t }=useTranslation('common');const{ control, formState, handleSubmit, watch, reset }=useForm<IUpdateGameTypeLimitParams>({defaultValues: {gameType: undefined,min: undefined,max: undefined,win: undefined,used: undefined,},});const[openEditDialog,setOpenEditDialog]=useState<boolean>(false);const[reload,setReload]=useState<boolean>(false);const{ gameTypeLimits, getAgenGameTypeLimit, handleGetLimit }=useGameTypeLimit();const{ updateGameTypeLimit }=useEditGameTypeLimit();functionhandleEditDialogClose(_: unknown,reason: string){if(reason==='backdropClick'||reason==='escapeKeyDown'){setOpenEditDialog(false);}}useEffect(()=>{getAgenGameTypeLimit({});},[reload]);useEffect(()=>{handleGetLimit();},[]);return(<Content><OSPageTitletitle={t('type_specific_settings')}/><Card><TableContainer><Table><TableHeadsx={{'& .MuiTableCell-root': {textAlign: 'center'}}}><TableRow>
...
...
...
</TableRow></TableHead><TableBodysx={{'& .MuiTableCell-root': {textAlign: 'center'}}}>{gameTypeLimits.map((game,index)=>{return(<TableRowkey={index}>
...
...
<TableCell><Box><Buttonvariant='outlined'size='small'onClick={()=>{reset({gameType: game.gametype,min: game.min,max: game.max,win: game.win,used: game.used,})setOpenEditDialog(true);}}>{t('edit')}</Button></Box></TableCell></TableRow>);})}</TableBody></Table></TableContainer><Stackdirection='column'justifyContent='space-between'alignItems='center'><StackalignItems='center'gap={1}style={{width: '100%',display: 'flex',justifyContent: 'space-evenly'}}></Stack></Stack></Card><Dialogopen={openEditDialog}onClose={handleEditDialogClose}fullWidth><DialogTitle>{t('type_specific_settings')}</DialogTitle><DialogContent><Stackgap={2}mx={1}><Box><Typographyvariant='body2'color='text.secondary'>{t('game_type')}</Typography><Typography>{watch('gameType')}</Typography></Box><Controllername='min'control={control}render={({ field })=><OSNumberFieldlabel='min_bet'value={field.value}onChange={field.onChange}/>}/><Controllername='max'control={control}render={({ field })=><OSNumberFieldlabel='max_bet'value={field.value}onChange={field.onChange}/>}/><Controllername='win'control={control}render={({ field })=><OSNumberFieldlabel='max_win'value={field.value}onChange={field.onChange}/>}/><Box><Controllername='used'control={control}render={({field})=><FormControlLabelcontrol={<Switchchecked={!!field.value}onChange={e=>field.onChange(e.target.checked)}/>}label={<Typographycolor='text.secondary'>{t('used')}</Typography>}labelPlacement='start'
sx={{gap: 1.5,mx: 0.5}}/>}/></Box><Typographymt={1}color='text.secondary'>{t('max_win_info')}</Typography><Stackdirection={'row'}mt={1}gap={1}><OSLoadingButtonlabel='save'fullWidthloading={formState.isSubmitting}onClick={handleSubmit(async(data)=>{// const isFormDirty = Object.keys(formState.dirtyFields).length > 0 <---- Normally worksif(!formState.isDirty){// <---- Not working on the first trysetOpenEditDialog(false)return}// fetch data// ...// ...setOpenEditDialog(false)})}/></Stack></Stack></DialogContent><DialogActions><ButtononClick={()=>setOpenEditDialog(false)}>{t('close')}</Button></DialogActions></Dialog></Content>);};exportdefaultTypeSpecificSettings;
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I'm using
react-hook-form 7.49.2
and ran into an issue whereformState.isDirty
doesn't seem to reflect the user's changes immediately after areset()
call — at least not on the first try.What I'm doing:
reset({ ...data })
to populate the form from an external source (e.g., editing an item).formState.isDirty
during form submission to check if the form was changed.But
formState.isDirty
is alwaysfalse
on the first submission, even if a field was changed. If I try again (with or without changes),isDirty
starts working correctly.What worked instead
That reliably detects field changes, even after
reset()
.Am I doing something wrong?
Is this expected behavior for
isDirty
? Or should it reflect changes right after a user modifies the form post-reset?I assumed
isDirty
should becometrue
as soon as any field changes from its reset/default value, but maybe there's something I'm missing about how it's tracked internally.I hope someone can clarify this for me. Thanks!
Code
Beta Was this translation helpful? Give feedback.
All reactions