This library contains utilities and react hooks.
import {} from '@anion155/react-hooks';
function useConst<T>(fabric: () => T): T;
Creates value on the first render, at render time.
const store = useConst(() => createStore());
type EffectCallback = () => (void | (() => void));
function useRenderEffect(effect: EffectCallback, deps: DependencyList): void;
Effect hook that runs at render time.
const ref = useRef(value);
useRenderEffect(() => {
ref.current = value;
}, [value]);
// ref.current === value
It is not guaranteed that cleanup function would be run during render. Specifically last cleanup before unmount is running as
useEffect
cleanup function.
type SetStateDispatcher<T> = (state: T | ((current: T) => T)) => void;
function useSetStateDispatcher(get: () => T, set: (value: T) => void): SetStateDispatcher<T>;
Creates stable set state action dispatcher function, which accepts next value or modifier.
const store = {
current: null,
get() { return this.current; },
set(next) { this.current = next },
};
const dispatcher = useSetStateDispatcher(
() => store.get(),
(next) => store.set(next),
);
dispatcher(10);
dispatcher(current => current * 2);
function useEventState<T>(stateInitial: StateInitial<T>): [T, (arg: T) => void];
function useEventState<As extends unknown[], T>(
stateInitial: StateInitial<T>,
project: (...args: As) => T,
deps: DependencyList
): [T, (...args: As) => void];
Creates event handler that stores event value in state.
const [value, handleChange] = useEventState('', (event) => event.target.value);
<>
<input onChange={handleChange} />
<span>Value: "{value}"</span>
</>
function useStableCallback<F>(
cb: (...args: Parameters<F>) => ReturnType<F>
): (...args: Parameters<F>) => ReturnType<F>;
Creates stable callback instance, result function never changes until unmounted.
const [counter, setCounter] = useState(1);
const cb = useStableCallback(() => {
setCounter(counter + 1);
});
useEffect(() => {
console.log('Runs one time only');
}, [cb]);
<button onClick={cb} />
function useFabric<T>(fabric: () => T, deps: DependencyList): T;
Creates value every time deps
are changed.
This is fully controlled version of
useMemo
, that will not followuseMemo
cache policies. SeeuseMemo caveats
const controller = useFabric(() => new ControllerClass(value), [value]);
function useInputState<T extends {}>(props: {
value: T;
defaultValue?: T;
onValueChange: (value: T) => void;
}): [T, SetStateDispatcher<T>];
function useInputState<T extends {}>(props: {
value?: T;
defaultValue: T;
onValueChange?: (value: T) => void;
}): [T, SetStateDispatcher<T>];
Creates tuple of value and set state acton dispatcher based on commonly used set of props value
, onValueChange
and defaultValue
.
Allows to create input components capable of being used as controlled component and as uncontrolled.
function CustomInput(props) {
const [value, setValue] = useInputState(props);
return <input value={value} onChange={e => setValue(e.value)} />
}
// uncontrolled version
<CustomInput defaultValue={5} />
// or as controlled input
const [value, setValue] = useState(5);
<CustomInput value={value} onValueChange={(e) => setValue(e.value)} />
function useLensedState<T, U>(
sourceState: readonly [T, SetStateDispatcher<T>],
getter: (state: T) => U,
setter: (value: U, state: T) => T
): [U, SetStateDispatcher<U>];
Creates state tuple binded to source state.
const formState = useState({ name: '', password: '' });
<Context.Provider value={formState}> />
const [name, setName] = useLensedState(
useContext(Context),
form => form.name,
(name, form) => ({ ...form, name })
);
setName(current => 'mr.' + current);
There is submodule with utility functions
import {} from '@anion155/react-hooks/utils';
function hasOwnProperty<P extends string, T>(obj: unknown, propertyName: P): obj is { [p in P]: T };
Type safe check if object has own property.
if (hasOwnProperty(obj, 'field')) {
obj.field; // ts now knows that obj has property 'field' of unknown type
}
class CanceledError extends Error;
type CancelablePromise<T> = Promise<T> & { cancel: () => void };
type CancelState = { canceled: boolean };
type CancelablePromiseExecutor<T> = (
resolve: (value: T | PromiseLike<T>) => void,
reject: (reason?: unknown) => void,
state: Readonly<CancelState>
) => void | { (): void };
function cancelablePromise<T>(executor: CancelablePromiseExecutor<T>): CancelablePromise<T>;
Creates cancelable promise.
const promise = cancelablePromise((resolve, reject, state) => {
const controller = new AbortController();
fetch('/something', { signal: controller.signal });
setTimeout(() => {
if (!state.canceled) return;
reject(new Error('Timeout'));
}, 1000);
return () => {
controller.abort();
};
});
promise.cancel();
function asyncDelay(timeout: number): CancelablePromise<void>;
Creates cancelable promise that will be resolved with timeout passed.
await asyncDelay(1000);
function compareProps(prev: DependencyList, next: DependencyList): boolean;
Compares two dependencies arrays, return true if they are equal.
compareProps(["same", 1], ["same", 2]) === 2;
function useRenderDispatcher<S>(
deps: DependencyList,
onChange: (state: S | undefined, prevDeps: DependencyList | undefined) => S
): S;
Creates cross render state based on deps.
const useMemo = (creator, deps) => useRenderDispatcher(deps, creator);