Skip to content

Commit 961b4d0

Browse files
authored
👍 close #12108 useController should subscribe to exact field name of form's state (#12109)
1 parent c01e64a commit 961b4d0

File tree

2 files changed

+94
-1
lines changed

2 files changed

+94
-1
lines changed

src/__tests__/useController.test.tsx

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ describe('useController', () => {
109109

110110
fireEvent.blur(screen.getAllByRole('textbox')[0]);
111111

112-
expect(renderCounter).toEqual([2, 5]);
112+
expect(renderCounter).toEqual([2, 3]);
113113
});
114114

115115
describe('checkbox', () => {
@@ -1012,4 +1012,96 @@ describe('useController', () => {
10121012
}),
10131013
);
10141014
});
1015+
1016+
it('should subscribe to exact form state update', () => {
1017+
type FormValues = {
1018+
test: string;
1019+
test_with_suffix: string;
1020+
};
1021+
1022+
const renderCounter: Record<keyof FormValues, number> = {
1023+
test: 0,
1024+
test_with_suffix: 0,
1025+
};
1026+
1027+
const ControlledInput = ({
1028+
name,
1029+
control,
1030+
}: {
1031+
name: keyof FormValues;
1032+
control: Control<FormValues>;
1033+
}) => {
1034+
const {
1035+
field,
1036+
fieldState: { error, isDirty },
1037+
} = useController({
1038+
name,
1039+
control,
1040+
rules: { required: 'is required' },
1041+
});
1042+
1043+
renderCounter[name]++;
1044+
1045+
return (
1046+
<div>
1047+
<input aria-label={name} {...field} />
1048+
{error && (
1049+
<p>
1050+
{name} {error.message}
1051+
</p>
1052+
)}
1053+
{isDirty && <p>{name} isDirty</p>}
1054+
</div>
1055+
);
1056+
};
1057+
1058+
const App = () => {
1059+
const { control } = useForm<FormValues>({
1060+
mode: 'onBlur',
1061+
defaultValues: {
1062+
test: '1234',
1063+
test_with_suffix: '1234',
1064+
},
1065+
});
1066+
return (
1067+
<form>
1068+
<ControlledInput name="test" control={control} />
1069+
<ControlledInput name="test_with_suffix" control={control} />
1070+
</form>
1071+
);
1072+
};
1073+
1074+
render(<App />);
1075+
1076+
expect(renderCounter).toEqual({ test: 1, test_with_suffix: 1 });
1077+
expect(screen.queryByText('test is required')).toBeNull();
1078+
expect(screen.queryByText('test_with_suffix is required')).toBeNull();
1079+
1080+
fireEvent.change(screen.getByRole('textbox', { name: 'test' }), {
1081+
target: {
1082+
value: '',
1083+
},
1084+
});
1085+
1086+
fireEvent.blur(screen.getByRole('textbox', { name: 'test' }));
1087+
1088+
expect(screen.getByText('test isDirty')).toBeVisible();
1089+
1090+
expect(renderCounter).toEqual({ test: 2, test_with_suffix: 1 });
1091+
1092+
fireEvent.change(
1093+
screen.getByRole('textbox', { name: 'test_with_suffix' }),
1094+
{
1095+
target: {
1096+
value: '',
1097+
},
1098+
},
1099+
);
1100+
1101+
fireEvent.blur(screen.getByRole('textbox', { name: 'test_with_suffix' }));
1102+
1103+
expect(screen.getByText('test_with_suffix isDirty')).toBeVisible();
1104+
1105+
expect(renderCounter).toEqual({ test: 2, test_with_suffix: 2 });
1106+
});
10151107
});

src/useController.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ export function useController<
6868
const formState = useFormState({
6969
control,
7070
name,
71+
exact: true,
7172
});
7273

7374
const _registerProps = React.useRef(

0 commit comments

Comments
 (0)