Skip to content

Commit edba16c

Browse files
authored
Merge pull request #783 from rvsia/rerenderForm
feat(manager): rerender form on basic functions
2 parents d150909 + c7d1b01 commit edba16c

File tree

7 files changed

+325
-123
lines changed

7 files changed

+325
-123
lines changed

packages/form-state-manager/src/files/use-field.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ const useField = ({
6666
beforeSubmit,
6767
afterSubmit,
6868
allowNull,
69+
silent,
6970
...props
7071
}: UseField): UseFieldData => {
7172
const { registerField, unregisterField, change, getFieldValue, blur, focus, formOptions, ...rest } = useContext(FormManagerContext);
@@ -83,7 +84,8 @@ const useField = ({
8384
internalId,
8485
defaultValue: dataType ? convertValue(defaultValue, dataType) : defaultValue,
8586
beforeSubmit,
86-
afterSubmit
87+
afterSubmit,
88+
silent
8789
});
8890

8991
return internalId;

packages/form-state-manager/src/tests/files/use-field-array.test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ import useFieldArray from '../../files/use-field-array';
66
import FormStateManager from '../../files/form-state-manager';
77

88
const DummyInput = (props) => {
9-
const { input, meta } = useField(props);
9+
const { input, meta } = useField({ ...props, silent: true });
1010
return <input {...input} />;
1111
};
1212

1313
const CompositeDummyInput = ({ name, ...props }) => {
14-
const firstField = useField({ ...props, name: `${name}.first-field` });
15-
const secondField = useField({ ...props, name: `${name}.second-field` });
14+
const firstField = useField({ ...props, name: `${name}.first-field`, silent: true });
15+
const secondField = useField({ ...props, name: `${name}.second-field`, silent: true });
1616
return (
1717
<Fragment>
1818
<input {...firstField.input} />

packages/form-state-manager/src/tests/performance/field-render-cycle.test.js

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import React, { useEffect } from 'react';
1+
import React, { useEffect, useContext, Fragment } from 'react';
22
import { act } from 'react-dom/test-utils';
33
import { mount } from 'enzyme';
44

55
import useField from '../../files/use-field';
66
import FormStateManager from '../../files/form-state-manager';
7+
import FormManagerContext from '../../files/form-manager-context';
78

89
const Field = ({ fieldSpy, ...props }) => {
910
const { input, id, ...rest } = useField(props);
@@ -70,4 +71,128 @@ describe('useField rendering cycle', () => {
7071
expect(fieldSpy.mock.calls[0][0]).toEqual('one');
7172
expect(fieldSpy.mock.calls[1][0]).toEqual('two');
7273
});
74+
75+
describe('callable function rerender forms', () => {
76+
let Tester;
77+
let renderSpy;
78+
79+
const Buttons = () => {
80+
const { formOptions } = useContext(FormManagerContext);
81+
82+
return (
83+
<Fragment>
84+
<button id="initialize" onClick={() => formOptions().initialize({ one: 'changed' })} />
85+
<button id="reset" onClick={() => formOptions().reset()} />
86+
<button id="resetfieldstate" onClick={() => formOptions().resetFieldState('one')} />
87+
<button id="submit" type="submit" />
88+
</Fragment>
89+
);
90+
};
91+
92+
beforeEach(() => {
93+
renderSpy = jest.fn();
94+
95+
Tester = ({ subscription }) => (
96+
<FormStateManager onSubmit={jest.fn()} subscription={subscription}>
97+
{() => {
98+
return (
99+
<form onSubmit={jest.fn()}>
100+
<Field fieldSpy={renderSpy} name="one" id="one" type="text" />
101+
<Buttons />
102+
</form>
103+
);
104+
}}
105+
</FormStateManager>
106+
);
107+
});
108+
109+
it('should rerender on initilize', async () => {
110+
const wrapper = mount(<Tester />);
111+
renderSpy.mockReset();
112+
113+
await act(async () => {
114+
wrapper.find('#initialize').simulate('click');
115+
});
116+
wrapper.update();
117+
118+
expect(renderSpy).toHaveBeenCalledTimes(1);
119+
expect(renderSpy.mock.calls[0][0]).toEqual('one');
120+
});
121+
122+
it('should rerender on resetFieldState', async () => {
123+
const wrapper = mount(<Tester />);
124+
renderSpy.mockReset();
125+
126+
await act(async () => {
127+
wrapper.find('input#one').prop('onChange')({ target: { value: 'foo', type: 'text' } });
128+
});
129+
wrapper.update();
130+
131+
renderSpy.mockReset();
132+
133+
await act(async () => {
134+
wrapper.find('#resetfieldstate').simulate('click');
135+
});
136+
wrapper.update();
137+
138+
expect(renderSpy).toHaveBeenCalledTimes(1);
139+
expect(renderSpy.mock.calls[0][0]).toEqual('one');
140+
});
141+
142+
it('should rerender on reset', async () => {
143+
const wrapper = mount(<Tester />);
144+
145+
await act(async () => {
146+
wrapper.find('input#one').prop('onChange')({ target: { value: 'foo', type: 'text' } });
147+
});
148+
wrapper.update();
149+
150+
renderSpy.mockReset();
151+
152+
await act(async () => {
153+
wrapper.find('#reset').simulate('click');
154+
});
155+
wrapper.update();
156+
157+
expect(renderSpy).toHaveBeenCalledTimes(1);
158+
expect(renderSpy.mock.calls[0][0]).toEqual('one');
159+
});
160+
161+
it('should rerender on focus & blur', async () => {
162+
const wrapper = mount(<Tester />);
163+
renderSpy.mockReset();
164+
165+
await act(async () => {
166+
wrapper.find('input#one').simulate('focus');
167+
});
168+
wrapper.update();
169+
170+
expect(renderSpy).toHaveBeenCalledTimes(1);
171+
expect(renderSpy.mock.calls[0][0]).toEqual('one');
172+
renderSpy.mockReset();
173+
174+
await act(async () => {
175+
wrapper.find('input#one').simulate('focus');
176+
});
177+
wrapper.update();
178+
179+
expect(renderSpy).toHaveBeenCalledTimes(0);
180+
181+
await act(async () => {
182+
wrapper.find('input#one').simulate('blur');
183+
});
184+
wrapper.update();
185+
186+
expect(renderSpy).toHaveBeenCalledTimes(1);
187+
expect(renderSpy.mock.calls[0][0]).toEqual('one');
188+
renderSpy.mockReset();
189+
190+
await act(async () => {
191+
wrapper.find('input#one').simulate('blur');
192+
});
193+
wrapper.update();
194+
195+
expect(renderSpy).toHaveBeenCalledTimes(0);
196+
});
197+
});
73198
});

packages/form-state-manager/src/tests/utils/manager-api.test.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -692,9 +692,11 @@ describe('managerApi', () => {
692692
managerApi().registerField({ ...field1 });
693693
managerApi().registerField({ ...field2 });
694694

695-
expect(renderField1).not.toHaveBeenCalled();
695+
expect(renderField1).toHaveBeenCalled(); // registeredFields was changed
696696
expect(renderField2).not.toHaveBeenCalled();
697697

698+
renderField1.mockReset();
699+
698700
managerApi().rerender(['values']);
699701

700702
expect(renderField1).toHaveBeenCalled();
@@ -727,9 +729,11 @@ describe('managerApi', () => {
727729
managerApi().registerField({ ...field1 });
728730
managerApi().registerField({ ...field2, subscription: { valid: true } });
729731

730-
expect(renderField1).not.toHaveBeenCalled();
732+
expect(renderField1).toHaveBeenCalled(); // registeredFields was changed
731733
expect(renderField2).not.toHaveBeenCalled();
732734

735+
renderField1.mockReset();
736+
733737
managerApi().rerender(['values']);
734738

735739
expect(renderField1).toHaveBeenCalled();

packages/form-state-manager/src/types/field-config.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import AnyObject from './any-object';
2-
import { Subscription } from './use-subscription';
2+
import { Subscription } from './use-field';
33
import { FieldRender } from './manager-api';
44
import { Validator } from './validate';
55

@@ -25,6 +25,7 @@ export interface FieldConfig extends AnyObject {
2525
data?: AnyObject;
2626
afterSubmit?: AfterSubmit;
2727
beforeSubmit?: BeforeSubmit;
28+
silent?: boolean;
2829
}
2930

3031
export default FieldConfig;

packages/form-state-manager/src/types/use-field.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export interface UseField extends AnyObject {
8181
afterSubmit?: AfterSubmit;
8282
beforeSubmit?: BeforeSubmit;
8383
allowNull?: boolean;
84+
silent?: boolean;
8485
}
8586

8687
export default UseField;

0 commit comments

Comments
 (0)