Skip to content

Commit

Permalink
Add use-singleton hook
Browse files Browse the repository at this point in the history
  • Loading branch information
mhdcodes committed Aug 12, 2024
1 parent 37ca4ec commit cf87d4e
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 10 deletions.
12 changes: 2 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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 <[email protected]>",
"contributors": [
{
Expand All @@ -21,9 +15,7 @@
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"files": ["dist"],
"exports": {
".": {
"import": {
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -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';
32 changes: 32 additions & 0 deletions src/use-singleton/use-singleton.test.ts
Original file line number Diff line number Diff line change
@@ -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);
});
});
15 changes: 15 additions & 0 deletions src/use-singleton/use-singleton.ts
Original file line number Diff line number Diff line change
@@ -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<ValueType>(fn: () => ValueType): ValueType {
const ref = useRef<{ value: ValueType }>();

if (!ref.current) {
ref.current = { value: fn() };
}

return ref.current.value;
}

0 comments on commit cf87d4e

Please sign in to comment.