1.2.0 • Published 4 years ago
use-callback-state v1.2.0
- reports when state got updated
- controls what could be set to the state
- helps with transformations
useState is about storing a variable, and changing it. However what if not everything could be set, and what if you have to react on state change?
Why?
- to react on state change in the same tick, not after as usual, causing potential state tearing and inconsistency.
- for input value validation or transformation
useReducer
useCallbackStateis quite similar touseReducer, it receives the oldstateand thenew, producing theresult. Use reducer does the same, andactioncould be action. However, you can't replace reducer, whilecallbackinuseCallbackStartwould always refer to a latest version.
Control
For state validation
import { useCallbackState } from 'use-callback-state';
const [state, setState] = useCallbackState(
2,
// allow only even numbers
(newState, oldState) => (newState % 2 ? oldState : newState)
);
state == 2;
setState(3);
state == 2; // 3 is odd number, the old state value was enforced
setState(4);
state == 4;For form values management
import { useCallbackState } from 'use-callback-state';
const [value, setValue, forceSetValue] = useCallbackState('John Doe', event => event.target.current);
return <input value={value} onChange={setValue} />;Report
const [state, setState] = useCallbackState(
42,
newState => {
onValueChange(newState);
} // not returning anything means "nothing transformed"
);
setState(10);
// call onValueChange(10)alternative
const [state, setState] = useState(42);
useEffect(() => onValueChange(state), [state]);
// call onValueChange(42) (did you want it?)
setState(10);
// call onValueChange(10)State separation
One state is "public" - what would be reported to the parent component, and another is "internal" - what user would see.
A good example - a DataInput where "public value" could be undefined if it's not valid
const [publicState, setPublicState] = useCallbackState(initialValue, onValueChange);
const [internalState, setInternalState] = useState(publicState);
useEffect(() => {
setPublicState(isValid(internalState) ? internalState : undefined);
}, [internalState]);
return (
<>
<input type="hidden" value={publicState} />
<input type="text" value={internalState} onChange={e => setInternalState(e.target.value)} />
</>
);See also
- use-callback-ref - the same
useRefbut it will callback.
License
MIT