diff --git a/package.json b/package.json index 9591a0c..b3e20b5 100644 --- a/package.json +++ b/package.json @@ -3,13 +3,7 @@ "version": "0.0.6", "description": "A collection of reusable react hooks for state and UI management", "homepage": "https://github.com/codiume/hooks.git", - "keywords": [ - "hooks", - "library", - "react", - "react-hooks", - "state" - ], + "keywords": ["hooks", "library", "react", "react-hooks", "state"], "author": "MHD ", "contributors": [ { @@ -21,9 +15,7 @@ "main": "./dist/index.cjs", "module": "./dist/index.js", "types": "./dist/index.d.ts", - "files": [ - "dist" - ], + "files": ["dist"], "exports": { ".": { "import": { diff --git a/src/index.ts b/src/index.ts index 820c2e3..f086873 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,3 @@ export { useQueue } from './use-queue/use-queue'; export { useScroll } from './use-scroll/use-scroll'; +export { useSingleton } from './use-singleton/use-singleton'; diff --git a/src/use-singleton/use-singleton.test.ts b/src/use-singleton/use-singleton.test.ts new file mode 100644 index 0000000..ad4369d --- /dev/null +++ b/src/use-singleton/use-singleton.test.ts @@ -0,0 +1,32 @@ +import { renderHook } from '@testing-library/react'; +import { describe, expect, it, vi } from 'vitest'; +import { useSingleton } from './use-singleton'; + +describe('useSingleton', () => { + it('should call the initializer function only once', () => { + const initializer = vi.fn(() => ({ value: 'singleton' })); + + const { rerender } = renderHook(() => useSingleton(initializer)); + + expect(initializer).toHaveBeenCalledTimes(1); + + rerender(); + rerender(); + + expect(initializer).toHaveBeenCalledTimes(1); + }); + + it('should return the same instance on re-renders', () => { + const initializer = () => ({ value: Math.random() }); + + const { result, rerender } = renderHook(() => useSingleton(initializer)); + + const firstInstance = result.current; + + rerender(); + + const secondInstance = result.current; + + expect(firstInstance).toBe(secondInstance); + }); +}); diff --git a/src/use-singleton/use-singleton.ts b/src/use-singleton/use-singleton.ts new file mode 100644 index 0000000..4b03379 --- /dev/null +++ b/src/use-singleton/use-singleton.ts @@ -0,0 +1,15 @@ +import { useRef } from 'react'; + +/** + * React hook for creating a singleton value. + * @see https://github.com/Andarist/use-constant + */ +export function useSingleton(fn: () => ValueType): ValueType { + const ref = useRef<{ value: ValueType }>(); + + if (!ref.current) { + ref.current = { value: fn() }; + } + + return ref.current.value; +}