Skip to content

Instantly share code, notes, and snippets.

@joelburton
Last active May 2, 2020 20:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joelburton/f370399c06b357590f30d8aba1c49994 to your computer and use it in GitHub Desktop.
Save joelburton/f370399c06b357590f30d8aba1c49994 to your computer and use it in GitHub Desktop.
import React, { useState, useEffect } from 'react';
import './App.css';
/** Hook for validating email-like state.
* - `initVal`: initial state (defaults to null; is not validated!)
* Returns [data, setData] functions, like useState() does.
*
* setData validates email: if input is invalid email string,
* doesn't set & returns false. If valid, sets & returns true. */
function useEmailValidatedState(initVal = null) {
const [data, setFn] = useState(initVal);
function validateEmailAndSet(possibleEmail) {
// very unrealistic validator for email--just an example
if (!possibleEmail.includes("@")) {
console.warn(`Invalid email: ${possibleEmail}`)
return false;
}
setFn(possibleEmail);
return true;
}
return [data, validateEmailAndSet]
}
/** Hook for validating state.
* - `validatorFunc`: callback, receives input & returns t/f
* - `initVal`: initial state (defaults to null; is not validated!)
* Returns [data, setData] functions, like useState() does.
*
* setData validates using validatorFunc: if input is invalid,
* doesn't set & returns false. If valid, sets & returns true. */
function useValidatedState(validatorFunc, initVal = null) {
const [data, setFn] = useState(initVal);
function validateAndSet(input) {
if (!validatorFunc(input)) {
console.warn(`Invalid: ${validatorFunc}, ${input}`)
return false;
} else {
setFn(input);
return true;
}
}
return [data, validateAndSet]
}
/** Hook for logged useEffects
* - `name`: name or description for effect (for log msg)
* - `effectFunc`: callback provided to useEffect
* - `deps`: dependencies provided to useEffect
*/
function useLoggedEffect(name, effectFunc, deps) {
useEffect(function loggedEffect() {
console.log("start of effect", name, deps);
const result = effectFunc();
console.log("end of effect", name, deps)
return result;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, deps);
}
/** demo of these */
const FORTUNES = ["yes", "no", "maybe"];
const choice = seq => seq[Math.floor(Math.random() * seq.length)];
function App() {
const [email, setEmail] = useEmailValidatedState();
const [oddNum, setOddNum] = useValidatedState(n => n % 2 === 1);
const [posNum, setPosNum] = useValidatedState(n => n >= 0);
const [item, setItem] = useState(0);
const [fortune, setFortune] = useState(choice(FORTUNES));
useLoggedEffect("newFortune", function newFortuneOnItemChange() {
setFortune(choice(FORTUNES));
}, [item]);
return (
<main>
<div>
<h3>useEmailValidatedState</h3>
{email}
<button onClick={evt => setEmail("a@a.com")}>
a@a.com
</button>
<button onClick={evt => setEmail("nope")}>
nope
</button>
</div>
<div>
<h3>useValidatedState</h3>
{oddNum}
<button onClick={evt => setOddNum(2)}>2</button>
<button onClick={evt => setOddNum(3)}>3</button>
</div>
<div>
{posNum}
<button onClick={evt => setPosNum(2)}>2</button>
<button onClick={evt => setPosNum(-3)}>3</button>
</div>
<div>
<h3>useLoggedEffect</h3>
{item}
<button onClick={evt => setItem(item + 1)}>item++</button>
{fortune}
</div>
</main>
);
}
export default App;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment