Skip to content

Commit

Permalink
refactor(useCounter): add docs and tests (#7828)
Browse files Browse the repository at this point in the history
- Делаем возврат функции useCounter похожим на useState
- Добавляем документацию
- Добавляем тестов
  • Loading branch information
SevereCloud authored Oct 24, 2024
1 parent 0f3f9db commit 9c0f507
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 20 deletions.
7 changes: 2 additions & 5 deletions packages/vkui/src/components/AppRoot/ScrollContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,8 @@ export const useScroll = (): ScrollContextInterface => React.useContext(ScrollCo
* Если счетчик больше нуля, требуется заблокировать прокрутку
*/
function useScrollLockController(enableScrollLock: () => void, disableScrollLock: () => void) {
const {
count,
increment: incrementScrollLockCounter,
decrement: decrementScrollLockCounter,
} = useCounter(0);
const [count, { increment: incrementScrollLockCounter, decrement: decrementScrollLockCounter }] =
useCounter(0);

const needLockScroll = count > 0;

Expand Down
77 changes: 77 additions & 0 deletions packages/vkui/src/hooks/useCounter.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { act } from 'react';
import { renderHook } from '@testing-library/react';
import { useCounter } from './useCounter';

describe('useCounter', () => {
it('returns default value', () => {
const { result } = renderHook(useCounter);
expect(result.current[0]).toEqual(0);
});

it('returns passed value with initialProps number', () => {
const { result } = renderHook(useCounter, {
initialProps: 99,
});
expect(result.current[0]).toEqual(99);
});
it('returns passed value with initialProps function', () => {
const { result } = renderHook(useCounter, {
initialProps: () => 99,
});
expect(result.current[0]).toEqual(99);
});

it('increment value', () => {
const { result } = renderHook(useCounter);
act(() => {
result.current[1].increment();
result.current[1].increment();
});
expect(result.current[0]).toEqual(2);
});
it('increment value with delta', () => {
const { result } = renderHook(useCounter);
act(() => {
result.current[1].increment(5);
result.current[1].increment(5);
});
expect(result.current[0]).toEqual(10);
});

it('decrement value', () => {
const { result } = renderHook(useCounter);
act(() => {
result.current[1].decrement();
result.current[1].decrement();
});
expect(result.current[0]).toEqual(-2);
});
it('decrement value with delta', () => {
const { result } = renderHook(useCounter);
act(() => {
result.current[1].decrement(5);
result.current[1].decrement(5);
});
expect(result.current[0]).toEqual(-10);
});

it('setCount value', () => {
const { result } = renderHook(useCounter);
act(() => {
result.current[1].setCount(5);
});
expect(result.current[0]).toEqual(5);
});

it('actions not change after re-render', () => {
const { result } = renderHook(useCounter);
const firstRenderActions = result.current[1];

act(() => {
result.current[1].increment();
});

expect(result.current[1]).toEqual(firstRenderActions);
expect(result.current[1].increment).toEqual(firstRenderActions.increment);
});
});
65 changes: 50 additions & 15 deletions packages/vkui/src/hooks/useCounter.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,61 @@
import * as React from 'react';

type UseCounterReturn = {
count: number;
increment: () => void;
decrement: () => void;
type Actions = {
/**
* Увеличивает значение счетчика и вызывает ре-рендер
*
* @param delta Значение на которое требуется увеличить счетчик. По умолчанию `1`
*/
increment: (delta?: number) => void;
/**
* Уменьшает значение счетчика и вызывает ре-рендер
*
* @param delta Значение на которое требуется увеличить счетчик. По умолчанию `1`
*/
decrement: (delta?: number) => void;

/**
* Функция, позволяющая обновить значение счетчика и вызвать ре-рендер
*/
setCount: React.Dispatch<React.SetStateAction<number>>;
};

/**
* Хук счетчика с возможностью задания начального значения и увеличения/уменьшения на 1.
* Хук счетчика с возможностью задания начального значения и увеличения/уменьшения значения.
*
* @param initialValue начальное значение счетчика. По умолчанию `0`
*
* ## Пример
*
* ```js
* const Component = () => {
* const [count, { increment, decrement, setCount }] = useCounter(0);
*
* return (
* <div>
* <div>count: {count}</div>
*
* <button onClick={() => increment()}> +1 </button>
* <button onClick={() => decrement()}> -1 </button>
* <button onClick={() => increment(5)}> +5 </button>
* <button onClick={() => decrement(5)}> -5 </button>
* <button onClick={() => setCount(0)}> set 0 </button>
* </div>
* );
* }
* ```
*/
export function useCounter(initialValue: number | (() => number) = 0): UseCounterReturn {
export function useCounter(initialValue: number | (() => number) = 0): [number, Actions] {
const [count, setCount] = React.useState(initialValue);

const increment = React.useCallback(() => setCount((x) => x + 1), []);

const decrement = React.useCallback(() => setCount((x) => x - 1), []);
const actions = React.useMemo(
() => ({
increment: (delta = 1) => setCount((x) => x + delta),
decrement: (delta = 1) => setCount((x) => x - delta),
setCount,
}),
[],
);

return {
count,
increment,
decrement,
setCount,
};
return [count, actions];
}

0 comments on commit 9c0f507

Please sign in to comment.