@@ -3,6 +3,7 @@ import { keyBy, get, every, some } from 'lodash';
33
44import { compose } from 'lib/lib';
55import { kDefaultValidator } from 'lib/validators';
6+import useSetState from 'lib/useSetState';
67
78// interface InputConfig {
89// name: string;
@@ -21,7 +22,7 @@ const defaultsFor = (configs, mapper) =>
2122 );
2223
2324/**
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
2526 */
2627export default function useForm(configs = []) {
2728 const byName = useMemo(() => keyBy(configs, 'name'), [configs]);
@@ -42,7 +43,7 @@ export default function useForm(configs = []) {
4243 // until there's a traditional state update.
4344
4445 // track focused states
45− const [focused, _setFocused] = useState(() =>
46+ const [focused, setFocused] = useSetState(() =>
4647 defaultsFor(configs, config => config.autoFocus && !config.disabled)
4748 );
4849 const focuses = useMemo(
@@ -50,23 +51,16 @@ export default function useForm(configs = []) {
5051 [configs, focused]
5152 );
5253
53− const setFocused = useCallback(
54− (name, value) => _setFocused(values => ({ ...values, [name]: value })),
55− [_setFocused]
56− );
57−
5854 // track whether or not input has been focused
59− const [hasBeenFocused, _setHasBeenFocused] = useState({});
60− const setHasBeenFocused = useCallback(
61− (name, value) =>
62− _setHasBeenFocused(values => ({ ...values, [name]: value })),
63− [_setHasBeenFocused]
64− );
55+ const [hasBeenFocused, setHasBeenFocused] = useSetState({});
6556
57+ // build fn that transforms a value by input name
6658 const transform = useCallback(
6759 (name, value) => compose(...get(byName, [name, 'transformers'], []))(value),
6860 [byName]
6961 );
62+
63+ // build fn that validates a value by input name
7064 const validate = useCallback(
7165 (name, value) =>
7266 compose(
@@ -76,28 +70,33 @@ export default function useForm(configs = []) {
7670 [byName]
7771 );
7872
73+ // on change, transform and set value
7974 const onChange = useCallback(
8075 name => e => setValue(name, transform(name, e.target.value)), //
8176 [setValue, transform]
8277 );
78+ // on focus, update focus
8379 const onFocus = useCallback(
84− name => e => setFocused(name, true), //
80+ name => e => setFocused({ [name]: true }), //
8581 [setFocused]
8682 );
83+
84+ // on blur, defocus and set has been focused
8785 const onBlur = useCallback(
8886 name => e => {
89− setFocused(name, false);
90− setHasBeenFocused(name, true);
87+ setFocused({ [name]: false });
88+ setHasBeenFocused({ [name]: false });
9189 },
9290 [setFocused, setHasBeenFocused]
9391 );
9492
95− // memo-compute whether or not the current value is valid
93+ // memo-compute validations of curent values
9694 const validations = useMemo(
9795 () => configs.map(config => validate(config.name, values[config.name])), //
9896 [configs, validate, values]
9997 );
10098
99+ // memo-compute the set of (perhaps changed by validation) data
101100 const datas = useMemo(() => validations.map(v => v.data), [validations]);
102101
103102 // the input has errored if it
@@ -137,6 +136,7 @@ export default function useForm(configs = []) {
137136 [configs, hasBeenFocused, focused, passes]
138137 );
139138
139+ // generate the list of input states
140140 const inputs = useMemo(
141141 () =>
142142 configs.map(
@@ -175,8 +175,10 @@ export default function useForm(configs = []) {
175175 ]
176176 );
177177
178− const pass = every(passes);
179− const error = some(errors);
178+ // did all of the inputs pass validation?
179+ const pass = useMemo(() => every(passes), [passes]);
180+ // did any of the inputs error?
181+ const error = useMemo(() => some(errors), [errors]);
180182
181183 return {
182184 inputs,