Skip to content

Commit

Permalink
feat(react): useDocumentTitle 커스텀 훅 추가 (#154)
Browse files Browse the repository at this point in the history
  • Loading branch information
ssi02014 authored May 23, 2024
1 parent d4f8f6d commit 589dd5b
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/tall-steaks-melt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@modern-kit/react': minor
---

feat(react): useDocumentTitle 커스텀 훅 추가 - @ssi02014
82 changes: 82 additions & 0 deletions docs/docs/react/hooks/useDoumentTitle.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { useDocumentTitle } from '@modern-kit/react';
import { useState } from 'react';

# useDocumentTitle

`SEO`와는 관계 없이 `document.title`을 동적으로 변경시켜주는 커스텀 훅입니다.

`preserveTitleOnUnmount` 옵션을 `true`로 준다면 `unmount` 시에 변경 된 타이틀로 유지할 수 있습니다.

<br />

## Code
[🔗 실제 구현 코드 확인](https://github.com/modern-agile-team/modern-kit/blob/main/packages/react/src/hooks/useDocumentTitle/index.ts)

## Interface
```ts title="typescript"
interface UseDocumentTitleOption {
preserveTitleOnUnmount?: boolean; // default: false
}

const useDocumentTitle: (
title: string,
{ preserveTitleOnUnmount }?: UseDocumentTitleOption
) => void;
```

## Usage
```tsx title="typescript"
import { useState } from 'react';
import { useDocumentTitle } from '@modern-kit/react';

const Example = () => {
const [title, setTitle] = useState('useDocumentTitle');
const [inputValue, setInputValue] = useState('');

const handleChangeTitle = () => {
setTitle(inputValue);
alert('타이틀이 변경됐습니다.');
};

useDocumentTitle(title, {
preserveTitleOnUnmount: false, // default: false
});

return (
<div>
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<button onClick={handleChangeTitle}>타이틀 변경</button>
</div>
);
};
```

## Example

export const Example = () => {
const [title, setTitle] = useState('useDocumentTitle');
const [inputValue, setInputValue] = useState('');
const handleChangeTitle = () => {
setTitle(inputValue);
alert('타이틀이 변경됐습니다.');
};
useDocumentTitle(title, {
preserveTitleOnUnmount: false, // default: false
});
return (
<div>
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<button onClick={handleChangeTitle}>타이틀 변경</button>
</div>
);
};

<Example />
1 change: 1 addition & 0 deletions packages/react/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export * from './useAsyncProcessQueue';
export * from './useBlockPromiseMultipleClick';
export * from './useClipboard';
export * from './useDebounce';
export * from './useDocumentTitle';
export * from './useFileReader';
export * from './useForceUpdate';
export * from './useImageStatus';
Expand Down
21 changes: 21 additions & 0 deletions packages/react/src/hooks/useDocumentTitle/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { useIsomorphicLayoutEffect } from '../useIsomorphicLayoutEffect';

interface UseDocumentTitleOption {
preserveTitleOnUnmount?: boolean;
}

export const useDocumentTitle = (
title: string,
{ preserveTitleOnUnmount = false }: UseDocumentTitleOption = {}
) => {
useIsomorphicLayoutEffect(() => {
const prevTitle = document.title;
document.title = title;

return () => {
if (!preserveTitleOnUnmount) {
document.title = prevTitle;
}
};
}, [title, preserveTitleOnUnmount]);
};
55 changes: 55 additions & 0 deletions packages/react/src/hooks/useDocumentTitle/useDoucmentTitle.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { renderHook } from '@testing-library/react';
import { useDocumentTitle } from '.';

const ORIGIN_TITLE = 'origin title';
const FIRST_CHANGE_TITLE = 'first change title';
const SECOND_CHANGE_TITLE = 'second change title';

beforeEach(() => {
document.title = ORIGIN_TITLE;
});

describe('useDocumentTitle', () => {
it('should update the document title', () => {
const { rerender, unmount } = renderHook(
({ title }) => useDocumentTitle(title),
{
initialProps: { title: FIRST_CHANGE_TITLE },
}
);

expect(document.title).toBe(FIRST_CHANGE_TITLE);

rerender({ title: SECOND_CHANGE_TITLE });

expect(document.title).toBe(SECOND_CHANGE_TITLE);

unmount();

expect(document.title).toBe(ORIGIN_TITLE);
});

it('should revert to the original title on unmount if preserveTitleOnUnmount is false', () => {
const { unmount } = renderHook(() =>
useDocumentTitle(FIRST_CHANGE_TITLE, { preserveTitleOnUnmount: false })
);

expect(document.title).toBe(FIRST_CHANGE_TITLE);

unmount();

expect(document.title).toBe(ORIGIN_TITLE);
});

it('should retain the changed title on unmount if preserveTitleOnUnmount is true', () => {
const { unmount } = renderHook(() =>
useDocumentTitle(FIRST_CHANGE_TITLE, { preserveTitleOnUnmount: true })
);

expect(document.title).toBe(FIRST_CHANGE_TITLE);

unmount();

expect(document.title).toBe(FIRST_CHANGE_TITLE);
});
});

0 comments on commit 589dd5b

Please sign in to comment.