use-callback-state
v1.2.0
Published
use State, but it will callback
Downloads
16
Readme
- 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
useCallbackState
is quite similar touseReducer
, it receives the oldstate
and thenew
, producing theresult
. Use reducer does the same, andaction
could be action. However, you can't replace reducer, whilecallback
inuseCallbackStart
would 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
useRef
but it will callback.
License
MIT