mirror of
https://github.com/streamich/react-use.git
synced 2026-01-25 14:17:16 +00:00
feat(useCounter): reworked with use of new resolveHookState function plus improved memory usage;
feat(resolveHookState): improved types;
This commit is contained in:
parent
9b5d0f2ad1
commit
befcf84c2c
@ -187,15 +187,15 @@ describe('should `console.error` on unexpected inputs', () => {
|
||||
|
||||
// @ts-ignore
|
||||
act(() => inc(false));
|
||||
expect(spy.mock.calls[0][0]).toBe('delta has to be a number, got boolean');
|
||||
expect(spy.mock.calls[0][0]).toBe('delta has to be a number or function returning a number, got boolean');
|
||||
|
||||
// @ts-ignore
|
||||
act(() => dec(false));
|
||||
expect(spy.mock.calls[1][0]).toBe('delta has to be a number, got boolean');
|
||||
expect(spy.mock.calls[1][0]).toBe('delta has to be a number or function returning a number, got boolean');
|
||||
|
||||
// @ts-ignore
|
||||
act(() => reset({}));
|
||||
expect(spy.mock.calls[2][0]).toBe('value has to be a number, got object');
|
||||
expect(spy.mock.calls[2][0]).toBe('value has to be a number or function returning a number, got object');
|
||||
|
||||
spy.mockRestore();
|
||||
});
|
||||
|
||||
@ -1,85 +1,89 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import useGetSet from './useGetSet';
|
||||
import { HookState, InitialHookState, resolveHookState } from './util/resolveHookState';
|
||||
|
||||
export interface CounterActions {
|
||||
inc: (delta?: number) => void;
|
||||
dec: (delta?: number) => void;
|
||||
get: () => number;
|
||||
set: (value: number) => void;
|
||||
reset: (value?: number) => void;
|
||||
set: (value: HookState<number>) => void;
|
||||
reset: (value?: HookState<number>) => void;
|
||||
}
|
||||
|
||||
export default function useCounter(
|
||||
initialValue: number = 0,
|
||||
initialValue: InitialHookState<number> = 0,
|
||||
max: number | null = null,
|
||||
min: number | null = null
|
||||
): [number, CounterActions] {
|
||||
typeof initialValue !== 'number' && console.error('initialValue has to be a number, got ' + typeof initialValue);
|
||||
let init = resolveHookState(initialValue);
|
||||
|
||||
typeof init !== 'number' && console.error('initialValue has to be a number, got ' + typeof initialValue);
|
||||
|
||||
if (typeof min === 'number') {
|
||||
initialValue = Math.max(initialValue, min);
|
||||
init = Math.max(init, min);
|
||||
} else if (min !== null) {
|
||||
console.error('min has to be a number, got ' + typeof min);
|
||||
}
|
||||
|
||||
if (typeof max === 'number') {
|
||||
initialValue = Math.min(initialValue, max);
|
||||
init = Math.min(init, max);
|
||||
} else if (max !== null) {
|
||||
console.error('max has to be a number, got ' + typeof max);
|
||||
}
|
||||
|
||||
const [get, setInternal] = useGetSet<number>(initialValue);
|
||||
const [get, setInternal] = useGetSet(init);
|
||||
|
||||
function set(value: number): void {
|
||||
const current = get();
|
||||
return [
|
||||
get(),
|
||||
useMemo(() => {
|
||||
const set = (newState: HookState<number>) => {
|
||||
const prevState = get();
|
||||
let rState = resolveHookState(newState, prevState);
|
||||
|
||||
if (current === value) {
|
||||
return;
|
||||
}
|
||||
if (prevState !== rState) {
|
||||
if (typeof min === 'number') {
|
||||
rState = Math.max(rState, min);
|
||||
}
|
||||
if (typeof max === 'number') {
|
||||
rState = Math.min(rState, max);
|
||||
}
|
||||
|
||||
if (typeof min === 'number') {
|
||||
value = Math.max(value, min);
|
||||
}
|
||||
if (typeof max === 'number') {
|
||||
value = Math.min(value, max);
|
||||
}
|
||||
prevState !== rState && setInternal(rState);
|
||||
}
|
||||
};
|
||||
|
||||
current !== value && setInternal(value);
|
||||
}
|
||||
return {
|
||||
get,
|
||||
set,
|
||||
inc: (delta: HookState<number> = 1) => {
|
||||
const rDelta = resolveHookState(delta, get());
|
||||
|
||||
const inc = useCallback(
|
||||
(delta: number = 1) => {
|
||||
typeof delta !== 'number' && console.error('delta has to be a number, got ' + typeof delta);
|
||||
if (typeof rDelta !== 'number') {
|
||||
console.error('delta has to be a number or function returning a number, got ' + typeof rDelta);
|
||||
}
|
||||
|
||||
set(get() + delta);
|
||||
},
|
||||
[max, min]
|
||||
);
|
||||
const dec = useCallback(
|
||||
(delta: number = 1) => {
|
||||
typeof delta !== 'number' && console.error('delta has to be a number, got ' + typeof delta);
|
||||
set((num: number) => num + rDelta);
|
||||
},
|
||||
dec: (delta: HookState<number> = 1) => {
|
||||
const rDelta = resolveHookState(delta, get());
|
||||
|
||||
set(get() - delta);
|
||||
},
|
||||
[max, min]
|
||||
);
|
||||
const reset = useCallback(
|
||||
(value: number = initialValue) => {
|
||||
typeof value !== 'number' && console.error('value has to be a number, got ' + typeof value);
|
||||
if (typeof rDelta !== 'number') {
|
||||
console.error('delta has to be a number or function returning a number, got ' + typeof rDelta);
|
||||
}
|
||||
|
||||
initialValue = value;
|
||||
set(value);
|
||||
},
|
||||
[max, min]
|
||||
);
|
||||
set((num: number) => num - rDelta);
|
||||
},
|
||||
reset: (value: HookState<number> = init) => {
|
||||
const rValue = resolveHookState(value, get());
|
||||
|
||||
const actions = {
|
||||
inc,
|
||||
dec,
|
||||
get,
|
||||
set,
|
||||
reset,
|
||||
};
|
||||
if (typeof rValue !== 'number') {
|
||||
console.error('value has to be a number or function returning a number, got ' + typeof rValue);
|
||||
}
|
||||
|
||||
return [get(), actions];
|
||||
init = rValue;
|
||||
set(rValue);
|
||||
},
|
||||
};
|
||||
}, [min, max]),
|
||||
];
|
||||
}
|
||||
|
||||
@ -5,14 +5,12 @@ export type InitialHookState<S> = S | InitialStateSetter<S>;
|
||||
export type HookState<S> = S | StateSetter<S>;
|
||||
export type ResolvableHookState<S> = S | StateSetter<S> | InitialStateSetter<S>;
|
||||
|
||||
export function resolveHookState<S>(newState: S | InitialStateSetter<S>): S;
|
||||
export function resolveHookState<S>(newState: Exclude<HookState<any>, StateSetter<any>>, currentState: S): S;
|
||||
// tslint:disable-next-line:unified-signatures
|
||||
export function resolveHookState<S>(newState: StateSetter<S>, currentState: S): S;
|
||||
export function resolveHookState<S>(newState: ResolvableHookState<S>, currentState?: S): S {
|
||||
export function resolveHookState<S, C extends S>(newState: StateSetter<S>, currentState: C): S;
|
||||
export function resolveHookState<S, C extends S>(newState: ResolvableHookState<S>, currentState?: C): S;
|
||||
export function resolveHookState<S, C extends S>(newState: ResolvableHookState<S>, currentState?: C): S {
|
||||
if (typeof newState === 'function') {
|
||||
return (newState as Function)(currentState);
|
||||
}
|
||||
|
||||
return newState as S;
|
||||
return newState;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user