@@ -3,6 +3,7 @@ import { keyBy, get, every, some } from 'lodash';
4import { compose } from 'lib/lib';
4import { compose } from 'lib/lib';
5import { kDefaultValidator } from 'lib/validators';
5import { kDefaultValidator } from 'lib/validators';
6+import useSetState from 'lib/useSetState';
7// interface InputConfig {
8// interface InputConfig {
8// name: string;
9// name: string;
@@ -21,7 +22,7 @@ const defaultsFor = (configs, mapper) =>
24− * useForm managest a set of inputs for rendering them in a loop
25+ * useForm manages a set of inputs for rendering them in a loop
26export default function useForm(configs = []) {
27export default function useForm(configs = []) {
27 const byName = useMemo(() => keyBy(configs, 'name'), [configs]);
28 const byName = useMemo(() => keyBy(configs, 'name'), [configs]);
@@ -42,7 +43,7 @@ export default function useForm(configs = []) {
42 // until there's a traditional state update.
43 // until there's a traditional state update.
44 // track focused states
45 // track focused states
45− const [focused, _setFocused] = useState(() =>
46+ const [focused, setFocused] = useSetState(() =>
46 defaultsFor(configs, config => config.autoFocus && !config.disabled)
47 defaultsFor(configs, config => config.autoFocus && !config.disabled)
48 const focuses = useMemo(
49 const focuses = useMemo(
@@ -50,23 +51,16 @@ export default function useForm(configs = []) {
50 [configs, focused]
51 [configs, focused]
53− const setFocused = useCallback(
54− (name, value) => _setFocused(values => ({ ...values, [name]: value })),
58 // track whether or not input has been focused
54 // track whether or not input has been focused
59− const [hasBeenFocused, _setHasBeenFocused] = useState({});
60− const setHasBeenFocused = useCallback(
55+ const [hasBeenFocused, setHasBeenFocused] = useSetState({});
62− _setHasBeenFocused(values => ({ ...values, [name]: value })),
57+ // build fn that transforms a value by input name
66 const transform = useCallback(
58 const transform = useCallback(
67 (name, value) => compose(...get(byName, [name, 'transformers'], []))(value),
59 (name, value) => compose(...get(byName, [name, 'transformers'], []))(value),
63+ // build fn that validates a value by input name
70 const validate = useCallback(
64 const validate = useCallback(
71 (name, value) =>
65 (name, value) =>
@@ -76,28 +70,33 @@ export default function useForm(configs = []) {
73+ // on change, transform and set value
79 const onChange = useCallback(
74 const onChange = useCallback(
80 name => e => setValue(name, transform(name, e.target.value)), //
75 name => e => setValue(name, transform(name, e.target.value)), //
81 [setValue, transform]
76 [setValue, transform]
78+ // on focus, update focus
83 const onFocus = useCallback(
79 const onFocus = useCallback(
84− name => e => setFocused(name, true), //
80+ name => e => setFocused({ [name]: true }), //
85 [setFocused]
81 [setFocused]
84+ // on blur, defocus and set has been focused
87 const onBlur = useCallback(
85 const onBlur = useCallback(
88 name => e => {
86 name => e => {
89− setFocused(name, false);
87+ setFocused({ [name]: false });
90− setHasBeenFocused(name, true);
88+ setHasBeenFocused({ [name]: false });
92 [setFocused, setHasBeenFocused]
90 [setFocused, setHasBeenFocused]
95− // memo-compute whether or not the current value is valid
93+ // memo-compute validations of curent values
96 const validations = useMemo(
94 const validations = useMemo(
97 () => configs.map(config => validate(config.name, values[config.name])), //
95 () => configs.map(config => validate(config.name, values[config.name])), //
98 [configs, validate, values]
96 [configs, validate, values]
99+ // memo-compute the set of (perhaps changed by validation) data
101 const datas = useMemo(() => validations.map(v => v.data), [validations]);
100 const datas = useMemo(() => validations.map(v => v.data), [validations]);
103 // the input has errored if it
102 // the input has errored if it
@@ -137,6 +136,7 @@ export default function useForm(configs = []) {
137 [configs, hasBeenFocused, focused, passes]
136 [configs, hasBeenFocused, focused, passes]
139+ // generate the list of input states
140 const inputs = useMemo(
140 const inputs = useMemo(
142 configs.map(
142 configs.map(
@@ -175,8 +175,10 @@ export default function useForm(configs = []) {
178+ // did all of the inputs pass validation?
178− const pass = every(passes);
179+ const pass = useMemo(() => every(passes), [passes]);
180+ // did any of the inputs error?
179− const error = some(errors);
181+ const error = useMemo(() => some(errors), [errors]);