Skip to content

Commit f6f25ff

Browse files
committed
feat(forms2): include form data observer custom hook
1 parent 9bcf7b8 commit f6f25ff

File tree

4 files changed

+68
-3
lines changed

4 files changed

+68
-3
lines changed

demo/Form2Examples.jsx

+18-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-disable no-console */
2-
import React, { useEffect } from 'react';
3-
import { Form2, FormInput2, FormSelect2, FormSwitch2, useFormControl2 } from '../dist/main';
2+
import React, { useEffect, useState } from 'react';
3+
import { Form2, FormInput2, FormSelect2, FormSwitch2, useFormControl2, useFormEffect } from '../dist/main';
44

55
export function Form2Examples() {
66
return (
@@ -75,6 +75,11 @@ export function Form2Examples() {
7575
<label htmlFor="">Version</label>
7676
<FormVersion />
7777
</div>
78+
79+
<div className="form-group">
80+
<label htmlFor="">Observer</label>
81+
<FormObserver />
82+
</div>
7883
<button className="btn btn-success">Submit</button>
7984
</Form2>
8085
</div>
@@ -106,3 +111,14 @@ function FormArrayOfObjects() {
106111

107112
return (getValue() || []).map((v, index) => <FormInput2 key={index} name={`arrObj[${index}].o`} />);
108113
}
114+
115+
function FormObserver() {
116+
const [state, setState] = useState(0);
117+
118+
useFormEffect((formData) => {
119+
console.log('FormObserver.formData :>> ', formData);
120+
setState((p) => p + 1);
121+
});
122+
123+
return <div>{state}</div>;
124+
}

src/forms2/helpers/useFormEffect.jsx

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { useContext, useEffect } from 'react';
2+
import { FormContext } from './useFormHelper';
3+
4+
export function useFormEffect(observerFn) {
5+
const formHelper = useContext(FormContext);
6+
7+
useEffect(() => {
8+
const unsubscribe = formHelper.subscribe(observerFn);
9+
10+
return () => unsubscribe();
11+
// eslint-disable-next-line react-hooks/exhaustive-deps
12+
}, []);
13+
}

src/forms2/helpers/useFormHelper.jsx

+36-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ export class FormHelper {
1111
this.formData = { ...initialValues };
1212
this.formControls = new Map();
1313
this.callHooks = debounce((fn) => fn(this.formData), debounceWait);
14+
this.listeners = [];
15+
this.nextListenerId = 0;
1416
}
1517

1618
register(name, formControl) {
@@ -25,7 +27,18 @@ export class FormHelper {
2527

2628
notify(name, value, hooks) {
2729
setValueByPath(this.formData, name, value);
28-
this.callHooks(hooks);
30+
this.callHooks((formData) => {
31+
hooks(formData);
32+
this.notifyListeners(formData);
33+
});
34+
}
35+
36+
notifyListeners(formData) {
37+
for (const listener of this.listeners) {
38+
setTimeout(() => {
39+
listener.observerFn(formData);
40+
}, 0);
41+
}
2942
}
3043

3144
updateFormData(data) {
@@ -41,6 +54,25 @@ export class FormHelper {
4154
}
4255
});
4356
}
57+
58+
unsubscribe(listenerId) {
59+
this.listeners = this.listeners.filter(({ id }) => id !== listenerId);
60+
}
61+
62+
subscribe(observerFn) {
63+
const listenerId = this.nextListenerId;
64+
65+
this.nextListenerId += 1;
66+
67+
this.listeners.push({
68+
id: listenerId,
69+
observerFn,
70+
});
71+
72+
return () => {
73+
this.unsubscribe(listenerId);
74+
};
75+
}
4476
}
4577

4678
export function useFormHelper(initialValues, { debounceWait, transform, onChange }) {
@@ -67,5 +99,8 @@ export function useFormHelper(initialValues, { debounceWait, transform, onChange
6799
register(name, formControl) {
68100
formHelper.current.register(name, formControl);
69101
},
102+
subscribe(observerFn) {
103+
return formHelper.current.subscribe(observerFn);
104+
},
70105
};
71106
}

src/forms2/index.jsx

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ export * from './FormInput';
33
export * from './FormSelect';
44
export * from './FormSwitch';
55
export * from './helpers/useFormControl';
6+
export * from './helpers/useFormEffect';

0 commit comments

Comments
 (0)