Last active
August 9, 2024 08:20
-
-
Save aliakakis/6f7c675e66a848689417ec8901a2500c to your computer and use it in GitHub Desktop.
Hook Validation for React
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {useRef} from 'react'; | |
import validators from './validators'; | |
/* Usage | |
const [user, setUser] = useState({ | |
username: '', | |
password: '', | |
}); | |
const [isUsernameInvalid, usernameErrors] = useValidate(user.username, ['isEmpty']); | |
const [isPasswordInvalid, passwordErrors] = useValidate(user.password, ['isEmpty']); | |
With passing extra params to a check | |
const [isIpInvalid, ipErrors] = useValidate(ipAddress, ['isEmpty', ['isValidIpAddressOrHostname', false]]); | |
<Button | |
disabled={isUsernameInvalid} | |
> | |
{'Login'} | |
</Button> | |
Vanilla version example | |
const errors = validate(ipAddress, ['isEmpty']); | |
With passing extra params to a check | |
const errors = validate(ipAddress, ['isEmpty', ['isValidIpAddressOrHostname', false]]); | |
*/ | |
/** | |
* useValidate hook | |
* @type {*[]} | |
* @param {string} value - The value to check against validations | |
* @param {(string | string[])[]} validations - Validations | |
* @return {[boolean, string[]]} | |
*/ | |
const useValidate = ( | |
value = '', | |
validations | |
) => { | |
/** @type {string[]} */ | |
const errors = []; | |
const init = useRef(false); /* When tests run for the first time do not run the tests */ | |
/** @param {boolean} initValue */ | |
const setInit = (initValue) => { | |
init.current = initValue; | |
}; | |
if (value.length) setInit(true); | |
if (!init.current) { | |
return [true, []]; | |
} | |
if (!validations) return [true, []]; | |
for (const validation of validations) { | |
let check = null; | |
if (validation instanceof Array) { | |
const [validator, param] = validation; | |
check = validators[validator](value, param); | |
} else { | |
check = validators[validation](value); | |
} | |
if (typeof check === 'string') errors.push(check); | |
} | |
return [!!errors.length, errors]; | |
}; | |
/* Vanilla version but fires check immediately */ | |
/** | |
* useValidate hook | |
* @type {*[]} | |
* @param {string} value - The value to check against validations | |
* @param {(string | string[])[]} validations - Validations | |
* @return {string[]} | |
*/ | |
export const validate = ( | |
value = '', | |
validations | |
) => { | |
/** @type {string[]} */ | |
const errors = []; | |
if (!validations) return []; | |
for (const validation of validations) { | |
let check = null; | |
if (validation instanceof Array) { | |
const [validator, param] = validation; | |
check = validators[validator](value, param); | |
} else { | |
check = validators[validation](value); | |
} | |
if (typeof check === 'string') errors.push(check); | |
} | |
return errors; | |
}; | |
export default useValidate; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Available validators | |
* @type {Object.<string, function(string, [param: * | Object.<*, *>]): boolean | string>} | |
*/ | |
const validators = { | |
isEmpty: (value = '') => !value && 'This field is mandatory', | |
isEqualWith: (value = '', valueToCompareWith = '') => | |
value !== valueToCompareWith && 'Fields are not equal', | |
isValidIpv4: (value = '') => { | |
const ipRegex = | |
/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/g; | |
return !ipRegex.test(value) && 'This is not a valid ip v4'; | |
}, | |
isValidMacAddress: (value = '') => { | |
const ipRegex = | |
/^[a-fA-F0-9]{2}(:[a-fA-F0-9]{2}){5}$/g; | |
return !ipRegex.test(value) && 'This is not a valid mac address'; | |
}, | |
isPasswordStrong: (value = '') => { | |
const ipRegex = | |
/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$ %^&*-]).{9,}$/g; | |
return ( | |
!ipRegex.test(value) && | |
'Length should be at least 9 characters. ' + | |
'Must contain uppercase letter. ' + | |
'Must contain lowercase letter. ' + | |
'Must contain digit. Must contain special character' | |
); | |
}, | |
isValidIpAddressOrHostname: (value = '', multiple = true) => { | |
const ipRegex = | |
// eslint-disable-next-line max-len | |
/^\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b|\b(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.)+([A-Za-z]|[A-Za-z][A-Za-z0-9-]*[A-Za-z0-9])\b$/g; | |
return !ipRegex.test(value) && (multiple ? | |
'You need one or more ip addresses and/or hostnames ' + | |
'e.g. 10.1.2.13, 10.1.2.14, dc1.yourdatacenter.com, dc2.yourdatacenter.com' : | |
'You need a valid ip address or hostname ' + | |
'e.g. 10.1.2.13 or dc1.yourdatacenter.com'); | |
}, | |
isValidIpAddressOrHostnameDomainSearch: (value = '') => { | |
const ipRegex = | |
// eslint-disable-next-line max-len | |
/^(^$)|(\b[a-zA-Z0-9]\b)|\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b|\b(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.?)+([A-Za-z]|[A-Za-z][A-Za-z0-9-]*[A-Za-z0-9])\b$/g; | |
return !ipRegex.test(value) && | |
'You need one or more ip addresses and/or hostnames ' + | |
'e.g. 10.1.2.13, 10.1.2.14, dc1.yourdatacenter.com, dc2.yourdatacenter.com'; | |
}, | |
}; | |
export default validators; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment