@homebound/form-state 2.7.0 → 2.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,18 +1,38 @@
1
1
  import { ObjectConfig, ObjectState } from "./formState";
2
2
  export declare type ObjectStateCache<T, I> = Record<string, [ObjectState<T>, I]>;
3
3
  declare type UseFormStatesOpts<T, I> = {
4
+ /**
5
+ * The config to use for each form state.
6
+ *
7
+ * Should be stable/useMemo'd.
8
+ */
4
9
  config: ObjectConfig<T>;
5
- /** Fired for each individual `ObjectState` when it's had a value change. */
10
+ /**
11
+ * Fired for each individual `ObjectState` when it's had a value change.
12
+ *
13
+ * Does not need to be stable/useMemo'd.
14
+ */
6
15
  autoSave?: (state: ObjectState<T>) => Promise<void>;
7
16
  /**
8
17
  * A hook to add custom, cross-field validation rules that can be difficult to setup directly in the config DSL.
9
18
  *
19
+ * This will be called once-per `ObjectState` instance, and so is effectively a `useEffect` hook with
20
+ * a `[config, objectState]` dependency.
21
+ *
10
22
  * Does not need to be stable/useMemo'd.
11
23
  */
12
24
  addRules?: (state: ObjectState<T>) => void;
13
- /** Given an input to `getObjectState`, returns the identity value that we'll cache that value's form state on. */
25
+ /**
26
+ * Given an input to `getObjectState`, returns the identity value that we'll cache that value's form state on.
27
+ *
28
+ * Does not need to be stable/useMemo'd.
29
+ */
14
30
  getId: (v: I) => string;
15
- /** Maps an input to `getObjectState` to the actual form shape `T`. */
31
+ /**
32
+ * Maps an input to `getObjectState` to the actual form shape `T`.
33
+ *
34
+ * Does not need to be stable/useMemo'd.
35
+ */
16
36
  map?: (input: Exclude<I, null | undefined>) => T;
17
37
  };
18
38
  export declare function useFormStates<T, I>(opts: UseFormStatesOpts<T, I>): {
@@ -6,7 +6,10 @@ const formState_1 = require("./formState");
6
6
  const utils_1 = require("./utils");
7
7
  function useFormStates(opts) {
8
8
  const { config, autoSave, getId, map, addRules } = opts;
9
- const objectStateCache = react_1.useMemo(() => ({}), [config]);
9
+ const objectStateCache = react_1.useMemo(() => ({}),
10
+ // Force resetting the cache if config changes
11
+ // eslint-disable-next-line react-hooks/exhaustive-deps
12
+ [config]);
10
13
  // Keep track of ObjectStates that triggered auto-save when a save was already in progress.
11
14
  const pendingAutoSaves = react_1.useRef([]);
12
15
  // Use a ref so our memo'ized `autoSave` always see the latest value
@@ -30,28 +33,30 @@ function useFormStates(opts) {
30
33
  }
31
34
  }
32
35
  }
33
- return {
34
- getObjectState: (input) => {
35
- const existing = objectStateCache[getId(input)];
36
- let form = existing === null || existing === void 0 ? void 0 : existing[0];
37
- // If it didn't exist, then add to the cache.
38
- if (!form) {
39
- form = formState_1.createObjectState(config, utils_1.initValue(config, map ? { map, input } : input), {
40
- maybeAutoSave: () => maybeAutoSave(form),
41
- });
42
- if (addRules) {
43
- addRules(form);
44
- }
45
- objectStateCache[getId(input)] = [form, input];
46
- }
47
- // If the source of truth changed, then update the existing state and return it.
48
- if (existing && existing[1] !== input) {
49
- form.set(utils_1.initValue(config, map ? { map, input } : input), { refreshing: true });
50
- existing[1] = input;
36
+ const getObjectState = react_1.useCallback((input) => {
37
+ const existing = objectStateCache[getId(input)];
38
+ let form = existing === null || existing === void 0 ? void 0 : existing[0];
39
+ // If it didn't exist, then add to the cache.
40
+ if (!form) {
41
+ form = formState_1.createObjectState(config, utils_1.initValue(config, map ? { map, input } : input), {
42
+ maybeAutoSave: () => maybeAutoSave(form),
43
+ });
44
+ if (addRules) {
45
+ addRules(form);
51
46
  }
52
- return form;
53
- },
54
- };
47
+ objectStateCache[getId(input)] = [form, input];
48
+ }
49
+ // If the source of truth changed, then update the existing state and return it.
50
+ if (existing && existing[1] !== input) {
51
+ form.set(utils_1.initValue(config, map ? { map, input } : input), { refreshing: true });
52
+ existing[1] = input;
53
+ }
54
+ return form;
55
+ },
56
+ // Allow the user to not stable-ize getId, map, addRules, and autoSave
57
+ // eslint-disable-next-line react-hooks/exhaustive-deps
58
+ [objectStateCache, config]);
59
+ return { getObjectState };
55
60
  }
56
61
  exports.useFormStates = useFormStates;
57
62
  // If the user's autoSave hook makes some last-minute `.set` calls to sneak
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homebound/form-state",
3
- "version": "2.7.0",
3
+ "version": "2.7.1",
4
4
  "author": "Homebound",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",