From 4292d19bf6d5a09852845f2f77da79b5b5b4f6b8 Mon Sep 17 00:00:00 2001 From: Tyler Waters Date: Sat, 7 Dec 2019 19:32:19 -0800 Subject: [PATCH 1/8] use useEffect for event firing --- src/use-validation.js | 23 +++++++++++++++++++---- test/utils.js | 2 +- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/use-validation.js b/src/use-validation.js index 370f9b6..d36b413 100644 --- a/src/use-validation.js +++ b/src/use-validation.js @@ -48,6 +48,9 @@ const useValidation = ( const timeoutRef = useRef(null) const argsRef = useRef(null) const [validated, setValidated] = useState(false) + const [valid, setValid] = useState(null) + const [error, setError] = useState(null) + const [invalid, setInvalid] = useState(null) const waitForValidation = useCallback( e => { @@ -64,14 +67,26 @@ const useValidation = ( (error, validity) => { const is_valid = error == null || error === false || error === '' const is_invalid = !is_valid - onValid?.(is_valid) - onError?.(is_valid ? null : getError(error, validity)) - onInvalid?.(is_invalid) + setValid(is_valid) + setInvalid(is_invalid) + setError(is_valid ? null : getError(error, validity)) setValidated(true) }, - [onError, onValid, onInvalid] + [setValid, setInvalid, setError, setValidated] ) + useEffect(() => { + onValid?.(valid) + }, [onValid, valid]) + + useEffect(() => { + onError?.(error) + }, [onError, error]) + + useEffect(() => { + onInvalid?.(invalid) + }, [onInvalid, invalid]) + const handleOnInvalid = useCallback( ({ target: element }) => updateState(new Error(element.validationMessage), element.validity), diff --git a/test/utils.js b/test/utils.js index 1fcb263..456c8cb 100644 --- a/test/utils.js +++ b/test/utils.js @@ -1 +1 @@ -export const wait = () => new Promise(resolve => setImmediate(resolve)) +export const wait = () => new Promise(resolve => setTimeout(resolve, 0)) From 783da0b0097537345b0fd7f4907ff0c01310a2b6 Mon Sep 17 00:00:00 2001 From: Tyler Waters Date: Sat, 7 Dec 2019 19:33:06 -0800 Subject: [PATCH 2/8] Add onValidated to the API --- readme.md | 3 +++ src/input.js | 5 ++++- src/use-validation.js | 7 ++++++- src/validator.js | 8 +++----- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/readme.md b/readme.md index 564ad09..38dfe8c 100644 --- a/readme.md +++ b/readme.md @@ -80,6 +80,7 @@ const example = () => ( onError={func} onInvalid={func} onValid={func} + onValidated={func} /> ) @@ -108,6 +109,8 @@ const example = () => ( - **onValid** _(bool) => void_ will be called after validation with a bool indicating the form field is valid +- **onValidated** _(bool) => void_ will be called after an input is validated. + Any additional props will be passed down to the underlying `input/select/textarea` element ### Validator diff --git a/src/input.js b/src/input.js index 782f88a..c722ede 100644 --- a/src/input.js +++ b/src/input.js @@ -18,6 +18,7 @@ const propTypes = { onError: func, onValid: func, onInvalid: func, + onValidated: func, name: string.isRequired // form elements must have name! } @@ -39,6 +40,7 @@ const createInput = inputType => { onError, onValid, onInvalid, + onValidated, ...rest }, ref @@ -64,7 +66,8 @@ const createInput = inputType => { click, onError, onValid, - onInvalid + onInvalid, + onValidated }) return React.createElement(inputType, { diff --git a/src/use-validation.js b/src/use-validation.js index d36b413..68e70c3 100644 --- a/src/use-validation.js +++ b/src/use-validation.js @@ -37,7 +37,8 @@ const useValidation = ( click, onError, onInvalid, - onValid + onValid, + onValidated } ) => { const ctx = useContext(FormContext) @@ -87,6 +88,10 @@ const useValidation = ( onInvalid?.(invalid) }, [onInvalid, invalid]) + useEffect(() => { + onValidated?.(validated) + }, [onValidated, validated]) + const handleOnInvalid = useCallback( ({ target: element }) => updateState(new Error(element.validationMessage), element.validity), diff --git a/src/validator.js b/src/validator.js index 9a6cece..1aaf64b 100644 --- a/src/validator.js +++ b/src/validator.js @@ -40,14 +40,11 @@ const Validator = ({ children, ...rest }) => { const [error, setError] = useState(null) const [valid, setValid] = useState(null) const [invalid, setInvalid] = useState(null) + const [validated, setValidated] = useState(null) const handleError = useCallback(e => setError(e), []) const handleValid = useCallback(e => setValid(e), []) const handleInvalid = useCallback(e => setInvalid(e), []) - const validated = useMemo(() => error || valid || invalid, [ - error, - invalid, - valid - ]) + const handleValidated = useCallback(e => setValidated(e), []) return mapDeep(children({ error, valid, invalid, validated }), item => { const myCtor = getCtorFromItem(item) if (myCtor == null) return item @@ -56,6 +53,7 @@ const Validator = ({ children, ...rest }) => { onError: handleError, onValid: handleValid, onInvalid: handleInvalid, + onValidated: handleValidated, ...item.props }) }) From f71091b51af269230b75f3d0a0565a4b1c83ec37 Mon Sep 17 00:00:00 2001 From: Tyler Waters Date: Sat, 7 Dec 2019 19:34:14 -0800 Subject: [PATCH 3/8] some is better than reduce here --- src/validator.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/validator.js b/src/validator.js index 1aaf64b..2f49924 100644 --- a/src/validator.js +++ b/src/validator.js @@ -14,10 +14,7 @@ import { Input, Select, TextArea } from './input' const mapDeep = (children, fn) => Children.map(children, (child, index) => isValidElement(child) && - Children.toArray(child.props.children).reduce( - (response, child) => response || isValidElement(child), - false - ) + Children.toArray(child.props.children).some(child => isValidElement(child)) ? fn( cloneElement(child, { ...child.props, From 435fd8d33be4c0306e9c110f41aa59300ca15a6d Mon Sep 17 00:00:00 2001 From: Tyler Waters Date: Sat, 7 Dec 2019 19:45:50 -0800 Subject: [PATCH 4/8] Readme, comments & Changelog --- CHANGELOG.MD | 8 ++++++++ readme.md | 22 +++++++++------------- src/form.js | 1 + 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 39bec9d..b932dc4 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -1,3 +1,11 @@ +# 1.2.0 + +- add onValidated - fired once after validation occurs. + +- now using useEffect for event firing. + +^-- this change should result in less calls to `onError` `onValidated`, `onInvalid` and `onValid` + # 1.1.0 - why are badges so difficult to get right? fixing it for real this time diff --git a/readme.md b/readme.md index 38dfe8c..85a376d 100644 --- a/readme.md +++ b/readme.md @@ -1,17 +1,13 @@ # React Form Validation - - npm version - - - build status - - - coverage - - - license (MIT) - +npm version +build status +coverage +license (MIT) The goal of this library is to implement the [Constraint Validation API](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#the-constraint-validation-api) in React while not getting in your way to do it. @@ -71,7 +67,7 @@ Input/Select/TextArea take all the same props. import { Input, Select, TextArea } from '@tswaters/react-form-validation' const example = () => ( <> - { * Form submit handler * Verify each of our inputs passes validation before calling onSubmit * But if validation fails, it won't ever be called - make sure to not submit the form. + * Calling `.persist()` because when async comes back, the `e.target` is null. */ const handleSubmit = useCallback( async e => { From e21d4fe5fdd3d82890d116ea0c5fac58317cb2eb Mon Sep 17 00:00:00 2001 From: Tyler Waters Date: Sat, 7 Dec 2019 19:46:16 -0800 Subject: [PATCH 5/8] Remove unused import, useMemo --- src/validator.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/validator.js b/src/validator.js index 2f49924..0a21e32 100644 --- a/src/validator.js +++ b/src/validator.js @@ -5,7 +5,6 @@ import { isValidElement, memo, useCallback, - useMemo, useState } from 'react' import { oneOfType, arrayOf, func } from 'prop-types' From 8ee43a1bf4ceda6a9c568b9028cf9814560bc591 Mon Sep 17 00:00:00 2001 From: Tyler Waters Date: Sat, 7 Dec 2019 19:48:38 -0800 Subject: [PATCH 6/8] fix serve configuration to actually work --- examples/index.html | 4 ++-- rollup.config.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/index.html b/examples/index.html index 86489c4..6bd426f 100644 --- a/examples/index.html +++ b/examples/index.html @@ -5,11 +5,11 @@ href="https://unpkg.com/bootstrap@4.3.1/dist/css/bootstrap.min.css" /> - + - +