Skip to content

Commit 2a901bb

Browse files
sukvvonkimyouknow
andauthored
feat(core/hooks): add 'useIsClient' hook (toss#219)
Co-authored-by: 김윤호 yunho <kimyouknow@naver.com>
1 parent c4e0195 commit 2a901bb

7 files changed

Lines changed: 140 additions & 0 deletions

File tree

.changeset/dirty-coats-fold.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'react-simplikit': patch
3+
---
4+
5+
feat(core/hooks): add 'useIsClient' hook
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { useIsClient } from './useIsClient.ts';
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# useIsClient
2+
3+
`useIsClient`는 클라이언트 환경에서만 `true`를 반환하는 리액트 훅이에요. 주로 클라이언트와 서버 사이드 렌더링(SSR)을 구분하기 위해 사용돼요. 컴포넌트가 클라이언트 환경에서 마운트된 후에만 `true`로 설정돼요.
4+
5+
## 인터페이스
6+
7+
```ts
8+
function useIsClient(): boolean;
9+
```
10+
11+
### 반환 값
12+
13+
<Interface
14+
name=""
15+
type="boolean"
16+
description="클라이언트 환경에서는 <code>true</code>를 반환하고, 그 외에는 <code>false</code>를 반환해요."
17+
/>
18+
19+
## 예시
20+
21+
```tsx
22+
import { useIsClient } from 'react-simplikit';
23+
24+
function ClientSideContent() {
25+
const isClient = useIsClient();
26+
27+
if (!isClient) {
28+
return <div>Loading...</div>;
29+
}
30+
31+
return <div>Client-side rendered content</div>;
32+
}
33+
```
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# useIsClient
2+
3+
`useIsClient` is a React hook that returns `true` only in the client-side environment. It is primarily used to differentiate between client-side and server-side rendering (SSR). The state is set to `true` only after the component is mounted in the client-side environment.
4+
5+
## Interface
6+
7+
```ts
8+
function useIsClient(): boolean;
9+
```
10+
11+
### Return Value
12+
13+
<Interface
14+
name=""
15+
type="boolean"
16+
description="Returns <code>true</code> in a client-side environment, and <code>false</code> otherwise."
17+
/>
18+
19+
## Example
20+
21+
```tsx
22+
import { useIsClient } from 'react-simplikit';
23+
24+
function ClientSideContent() {
25+
const isClient = useIsClient();
26+
27+
if (!isClient) {
28+
return <div>Loading...</div>;
29+
}
30+
31+
return <div>Client-side rendered content</div>;
32+
}
33+
```
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { describe, expect, it } from 'vitest';
2+
3+
import { renderHookSSR } from '../../_internal/test-utils/renderHookSSR.tsx';
4+
5+
import { useIsClient } from './useIsClient.ts';
6+
7+
describe('useIsClient', () => {
8+
it('is safe on server side rendering', async () => {
9+
const result = renderHookSSR.serverOnly(() => useIsClient());
10+
11+
expect(result.current).toBe(false);
12+
});
13+
14+
it('should return true after hydration on the client', async () => {
15+
const { result } = await renderHookSSR(() => useIsClient());
16+
17+
expect(result.current).toBe(true);
18+
});
19+
});
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { useEffect, useState } from 'react';
2+
3+
/**
4+
* @description
5+
* `useIsClient` is a React hook that returns `true` only in the client-side environment.
6+
* It is primarily used to differentiate between client-side and server-side rendering (SSR).
7+
* The state is set to `true` only after the component is mounted in the client-side environment.
8+
*
9+
* @returns {boolean} Returns `true` in a client-side environment, and `false` otherwise.
10+
*
11+
* @example
12+
* function ClientSideContent() {
13+
* const isClient = useIsClient();
14+
*
15+
* if (!isClient) {
16+
* return <div>Loading...</div>; // Rendered on the server side
17+
* }
18+
*
19+
* return <div>Client-side rendered content</div>; // Rendered on the client side
20+
* }
21+
*
22+
* @example
23+
* function ClientOnlyMap() {
24+
* const isClient = useIsClient();
25+
*
26+
* if (!isClient) return null;
27+
*
28+
* return <div id="map" />;
29+
* }
30+
*
31+
* @example
32+
* function ClientTheme() {
33+
* const isClient = useIsClient();
34+
*
35+
* const theme = isClient ? localStorage.getItem('theme') : 'light';
36+
*
37+
* return <div>Current theme: {theme}</div>;
38+
* }
39+
*/
40+
export function useIsClient() {
41+
const [isClient, setIsClient] = useState(false);
42+
43+
useEffect(function syncClientState() {
44+
setIsClient(true);
45+
}, []);
46+
47+
return isClient;
48+
}

packages/core/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export { useImpressionRef } from './hooks/useImpressionRef/index.ts';
1515
export { useInputState } from './hooks/useInputState/index.ts';
1616
export { useIntersectionObserver } from './hooks/useIntersectionObserver/index.ts';
1717
export { useInterval } from './hooks/useInterval/index.ts';
18+
export { useIsClient } from './hooks/useIsClient/index.ts';
1819
export { useIsomorphicLayoutEffect } from './hooks/useIsomorphicLayoutEffect/index.ts';
1920
export { useLoading } from './hooks/useLoading/index.ts';
2021
export { useLongPress } from './hooks/useLongPress/index.ts';

0 commit comments

Comments
 (0)