From 03bf6f586bab980c5773b5ff8b34f278d2669c92 Mon Sep 17 00:00:00 2001 From: Rully saputra Date: Wed, 15 Jul 2026 20:31:48 +0700 Subject: [PATCH] feat: add server checker for useHash hook --- src/misc/isServer.ts | 1 + src/useHash.ts | 21 +++++++++++---------- tests/useHash.test.ts | 15 +++++++++++++++ 3 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 src/misc/isServer.ts diff --git a/src/misc/isServer.ts b/src/misc/isServer.ts new file mode 100644 index 0000000000..df38247934 --- /dev/null +++ b/src/misc/isServer.ts @@ -0,0 +1 @@ +export const isServer = () => typeof window === 'undefined'; diff --git a/src/useHash.ts b/src/useHash.ts index 6d936d333a..323c7a5de0 100644 --- a/src/useHash.ts +++ b/src/useHash.ts @@ -1,25 +1,26 @@ -import { useCallback, useState } from 'react'; -import useLifecycles from './useLifecycles'; +import { useCallback, useEffect, useState } from 'react'; import { off, on } from './misc/util'; +import { isServer } from './misc/isServer'; /** * read and write url hash, response to url hash change */ + export const useHash = () => { - const [hash, setHash] = useState(() => window.location.hash); + const [hash, setHash] = useState(() => (isServer() ? '' : window.location.hash)); const onHashChange = useCallback(() => { setHash(window.location.hash); }, []); - useLifecycles( - () => { - on(window, 'hashchange', onHashChange); - }, - () => { + useEffect(() => { + if (isServer()) return; + on(window, 'hashchange', onHashChange); + + return () => { off(window, 'hashchange', onHashChange); - } - ); + }; + }, []); const _setHash = useCallback( (newHash: string) => { diff --git a/tests/useHash.test.ts b/tests/useHash.test.ts index da2f76e689..367224da68 100644 --- a/tests/useHash.test.ts +++ b/tests/useHash.test.ts @@ -1,5 +1,9 @@ import { renderHook, act } from '@testing-library/react-hooks'; import { useHash } from '../src/useHash'; +import { isServer } from '../src/misc/isServer'; + +jest.mock('../src/misc/isServer'); +const mockIsServer = isServer as jest.MockedFunction; (global as any).window = Object.create(window); let mockHash = '#'; @@ -18,9 +22,20 @@ Object.defineProperty(window, 'location', { }); beforeEach(() => { + mockIsServer.mockReturnValue(false); window.location.hash = '#'; }); +test('returns an empty hash when rendered on the server', () => { + mockIsServer.mockReturnValue(true); + window.location.hash = '#abc'; + + const { result } = renderHook(() => useHash()); + + const hash = result.current[0]; + expect(hash).toBe(''); +}); + test('returns current url hash', () => { window.location.hash = '#abc';