From 266d4f6853bb94d6fa6ce1f845ba17fb1da2a463 Mon Sep 17 00:00:00 2001 From: krutoo Date: Thu, 29 Jan 2026 00:17:40 +0500 Subject: [PATCH] feat(react)!: usePreviousState removed Hook is removed because it has no common use BREAKING CHANGE: usePreviousState removed usePreviousState removed, there is no alternatives in the library --- eslint.config.ts | 5 +++- scripts/{git-hooks.js => git-hooks.ts} | 0 src/react/mod.ts | 1 - src/react/query/use-mutation.ts | 8 ++++++- src/react/use-intersection.ts | 4 +++- src/react/use-outside-click.ts | 6 ++++- src/react/use-previous-state.ts | 32 ------------------------- src/react/use-resize.ts | 4 +++- src/react/use-visual-viewport.ts | 8 ++++++- src/store/__test__/create-store.test.ts | 17 +++++++++++++ 10 files changed, 46 insertions(+), 39 deletions(-) rename scripts/{git-hooks.js => git-hooks.ts} (100%) delete mode 100644 src/react/use-previous-state.ts diff --git a/eslint.config.ts b/eslint.config.ts index 446bf15..b9a5578 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -33,6 +33,7 @@ const config: ReturnType = defineConfig([ 'object-shorthand': 'error', 'no-console': 'error', eqeqeq: 'error', + 'no-param-reassign': 'error', '@typescript-eslint/no-explicit-any': 'off', 'no-shadow': 'off', '@typescript-eslint/no-shadow': 'error', @@ -44,8 +45,10 @@ const config: ReturnType = defineConfig([ ], }, }, + + // CommonJS { - files: ['**/*.cjs'], + files: ['**/*.{cjs,cts}'], rules: { '@typescript-eslint/no-require-imports': 'off', }, diff --git a/scripts/git-hooks.js b/scripts/git-hooks.ts similarity index 100% rename from scripts/git-hooks.js rename to scripts/git-hooks.ts diff --git a/src/react/mod.ts b/src/react/mod.ts index 96e7987..a73081b 100644 --- a/src/react/mod.ts +++ b/src/react/mod.ts @@ -4,7 +4,6 @@ export * from './use-debounce-state.ts'; export * from './use-dependent-ref.ts'; export * from './use-isomorphic-layout-effect.ts'; export * from './use-latest-ref.ts'; -export * from './use-previous-state.ts'; export * from './use-stable-callback.ts'; export * from './use-mounted.ts'; diff --git a/src/react/query/use-mutation.ts b/src/react/query/use-mutation.ts index e3ef78b..b26ac33 100644 --- a/src/react/query/use-mutation.ts +++ b/src/react/query/use-mutation.ts @@ -58,7 +58,13 @@ export function useMutation({ instance.events.removeEventListener('failed', onFailed); instance.events.removeEventListener('changed', onChanged); }; - }, [instance, onSuccessRef, onErrorRef]); + }, [ + instance, + + // stable: + onSuccessRef, + onErrorRef, + ]); const mutate = useStableCallback(async (payload: P): Promise => { return await instance.execute(() => mutation(payload)); diff --git a/src/react/use-intersection.ts b/src/react/use-intersection.ts index 1f84c1d..5199a98 100644 --- a/src/react/use-intersection.ts +++ b/src/react/use-intersection.ts @@ -79,10 +79,12 @@ export function useIntersection( }; }, [ ref, - callbackRef, readyOptions, getObserver, + // stable: + callbackRef, + // eslint-disable-next-line react-hooks/exhaustive-deps ...extraDeps, ]); diff --git a/src/react/use-outside-click.ts b/src/react/use-outside-click.ts index 768fd33..7570797 100644 --- a/src/react/use-outside-click.ts +++ b/src/react/use-outside-click.ts @@ -42,5 +42,9 @@ export function useOutsideClick( return () => { document.documentElement.removeEventListener('click', handleClick, handleClickOptions); }; - }, [innerRef, callbackRef]); + }, [ + // stable: + innerRef, + callbackRef, + ]); } diff --git a/src/react/use-previous-state.ts b/src/react/use-previous-state.ts deleted file mode 100644 index 38dc446..0000000 --- a/src/react/use-previous-state.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { useEffect, useRef } from 'react'; - -/** - * Hook of previous state of a value. - * @param actualValue Actual value. - * @returns Previous value or initial value (if present) or undefined (only first time). - */ -export function usePreviousState(actualValue: T): T | undefined; - -/** - * Hook of previous state of a value. - * @param actualValue Actual value. - * @param initialValue Initial value. - * @returns Previous value or initial value (if present) or undefined (only first time). - */ -export function usePreviousState(actualValue: T, initialValue: I): T | I; - -/** - * Hook of previous state of a value. - * @param actualValue Actual value. - * @param initialValue Initial value. - * @returns Previous value or initial value (if present) or undefined (only first time). - */ -export function usePreviousState(actualValue: unknown, initialValue?: unknown) { - const ref = useRef(initialValue); - - useEffect(() => { - ref.current = actualValue; - }, [actualValue]); - - return ref.current; -} diff --git a/src/react/use-resize.ts b/src/react/use-resize.ts index 328b89c..ec1e461 100644 --- a/src/react/use-resize.ts +++ b/src/react/use-resize.ts @@ -67,10 +67,12 @@ export function useResize( }; }, [ ref, - callbackRef, getObserver, readyOptions, + // stable: + callbackRef, + // eslint-disable-next-line react-hooks/exhaustive-deps ...extraDeps, ]); diff --git a/src/react/use-visual-viewport.ts b/src/react/use-visual-viewport.ts index 90d1d39..a3b3d5d 100644 --- a/src/react/use-visual-viewport.ts +++ b/src/react/use-visual-viewport.ts @@ -147,7 +147,13 @@ export function useVisualViewport({ sync(); return observe(visualViewport, sync); - }, [getVisualViewport, modeRef, handleChange]); + }, [ + getVisualViewport, + + // stable: + modeRef, + handleChange, + ]); return state; } diff --git a/src/store/__test__/create-store.test.ts b/src/store/__test__/create-store.test.ts index e5a1d10..d7ac3db 100644 --- a/src/store/__test__/create-store.test.ts +++ b/src/store/__test__/create-store.test.ts @@ -38,4 +38,21 @@ describe('createStore', () => { store.set(-100); expect(spy.mock.callCount()).toBe(1); }); + + test('methods should works without call context', () => { + const { get, set, subscribe } = createStore(1); + + const spy = mock.fn(); + const unsubscribe = subscribe(spy); + + expect(get()).toBe(1); + expect(spy.mock.callCount()).toBe(0); + + expect(set(123)); + expect(spy.mock.callCount()).toBe(1); + + unsubscribe(); + expect(set(234)); + expect(spy.mock.callCount()).toBe(1); + }); });