Skip to content

Commit

Permalink
feat(@yourssu/react): create useSecTimer, useMediaQuery (#22)
Browse files Browse the repository at this point in the history
* docs: modify useInterval md & add english md

* feat(react): create useSecTimer

* feat(react): create useMediaQuery
  • Loading branch information
Hanna922 authored Jun 7, 2024
1 parent 41844f3 commit 7f0fd57
Show file tree
Hide file tree
Showing 12 changed files with 438 additions and 4 deletions.
1 change: 1 addition & 0 deletions packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "@yourssu/react",
"private": false,
"version": "0.1.0",
"sideEffects": false,
"description": "Yourssu React Package",
"keywords": [
"yourssu",
Expand Down
36 changes: 36 additions & 0 deletions packages/react/src/hooks/useInterval.en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# useInterval

`useInterval` custom hook is used to execute a given callback function at a specified interval.
This hook utilizes `useEffect` and `useRef` to manage the callback function and interval timer.

## API

```ts
useInterval(callback: () => void, interval: number)
```

#### Parameters

- `callback` (function): The callback function to be executed.
- `interval` (number): The interval (in milliseconds) at which the callback function will be executed.

## Example

```jsx
const MyComponent = () => {
useInterval(() => {
console.log('This will run every second');
}, 1000);

return <div>Check the console</div>;
};
```

## Notes

This hook internally uses two `useEffect` hooks:

1. The first `useEffect` keeps the callback function up to date.
2. The second `useEffect` sets up a timer to execute the callback function at the given interval.

If the `interval` changes or is set to `null`, the timer will be updated or cleared accordingly.
17 changes: 13 additions & 4 deletions packages/react/src/hooks/useInterval.ko.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
# useInterval

`useInterval` 커스텀 훅은 특정 간격마다 주어진 콜백 함수를 실행하기 위해 사용됩니다. 이 훅은 `useEffect``useRef`를 활용하여 콜백 함수와 간격 타이머를 관리합니다.
`useInterval` 커스텀 훅은 특정 간격마다 주어진 콜백 함수를 실행하기 위해 사용됩니다.
이 훅은 `useEffect``useRef`를 활용하여 콜백 함수와 간격 타이머를 관리합니다.

## 매개변수
## API

- `callback`: 실행될 콜백 함수입니다.
- `interval`: 콜백 함수가 실행될 간격(밀리초)입니다.
```ts
useInterval(callback: () => void, interval: number)
```

#### Parameters

- `callback` (function): 실행될 콜백 함수입니다.
- `interval` (number): 콜백 함수가 실행될 간격(밀리초)입니다.

## Example

Expand All @@ -20,7 +27,9 @@ const MyComponent = () => {
```

## Notes

이 훅은 내부적으로 두 개의 `useEffect`를 사용합니다:

1. 첫 번째 `useEffect`는 콜백 함수를 최신 상태로 유지합니다.
2. 두 번째 `useEffect`는 주어진 간격마다 콜백 함수를 실행하는 타이머를 설정합니다.

Expand Down
43 changes: 43 additions & 0 deletions packages/react/src/hooks/useMediaQuery.en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# useMediaQuery

`useMediaQuery` is a custom React hook that allows you to easily use media queries in your React components.
It leverages the `window.matchMedia` API to listen for changes in the viewport and determine if a specified media query matches the current state of the viewport.

## API

```ts
useMediaQuery(query: string);
```

### Parameters

- `query` (string): A media query string that you want to match against the current viewport.

### Return value

- `isMatch` (boolean): A boolean value indicating whether the media query matches the current viewport.

## Examples

```jsx
import { useMediaQuery } from './useMediaQuery';

const MyComponent = () => {
const isLargeScreen = useMediaQuery('(min-width: 1024px)');

return (
<div>
{isLargeScreen ? (
<p>The viewport is at least 1024 pixels wide</p>
) : (
<p>The viewport is less than 1024 pixels wide</p>
)}
</div>
);
};
```

## Notes

- This hook relies on the `window.matchMedia` API, which is widely supported in modern browsers. However, for older browsers, you might need to include a polyfill.
- Ensure that the `query` parameter is correctly formatted as a valid media query string.
43 changes: 43 additions & 0 deletions packages/react/src/hooks/useMediaQuery.ko.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# useMediaQuery

`useMediaQuery`는 React 컴포넌트에서 미디어 뭐리를 쉽게 사용할 수 있게 해주는 커스텀 React 훅입니다.
이 훅은 `window.matchMedia` API를 활용하여 뷰포트의 상태 변화를 감지하고 지정된 미디어 쿼리가 현재 뷰포트와 일치하는지 확인합니다.

## API

```ts
useMediaQuery(query: string);
```

### Parameters

- `query` (string): 현재 뷰포트와 일치시키고자 하는 미디어 쿼리 문자열입니다.

### Return value

- `isMatch` (boolean): 미디어 쿼리가 현재 뷰포트와 일치하는지 boolean 값으로 나타냅니다.

## Examples

```jsx
import { useMediaQuery } from './useMediaQuery';

const MyComponent = () => {
const isLargeScreen = useMediaQuery('(min-width: 1024px)');

return (
<div>
{isLargeScreen ? (
<p>The viewport is at least 1024 pixels wide</p>
) : (
<p>The viewport is less than 1024 pixels wide</p>
)}
</div>
);
};
```

## Notes

- 이 훅은 최신 브라우저에서 널리 지원되는 `window.matchMedia` API에 의존합니다. 그러나 오래된 브라우저의 경우 폴리필을 포함해야 할 수도 있습니다.
- `query` 매개변수가 유효한 미디어 쿼리 문자열로 올바르게 포맷되어 있는지 확인해야 합니다.
55 changes: 55 additions & 0 deletions packages/react/src/hooks/useMediaQuery.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { renderHook } from '@testing-library/react';
import { describe, it, expect, vi } from 'vitest';

import { useMediaQuery } from './useMediaQuery';

// Browser environment
describe('useMediaQuery - Browser', () => {
it('should return true when the query matches', () => {
const query = '(min-width: 600px)';

// setting jsdom environment
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: (query: string) => ({
matches: query === '(min-width: 600px)',
media: query,
onchange: null,
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
}),
});

const { result } = renderHook(() => useMediaQuery(query));
expect(result.current).toBe(true);
});

it('should return false when the query does not match', () => {
const query = '(max-width: 599px)';

// setting jsdom environment
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: (query: string) => ({
matches: query === '(max-width: 599px)',
media: query,
onchange: null,
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
}),
});

const { result } = renderHook(() => useMediaQuery(query));
expect(result.current).toBe(true);
});
});

// Node.js environment
describe('useMediaQuery - Node.js', () => {
it('should return false when running on server side', () => {
const query = '(min-width: 600px)';

const { result } = renderHook(() => useMediaQuery(query));
expect(result.current).toBe(false);
});
});
29 changes: 29 additions & 0 deletions packages/react/src/hooks/useMediaQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useEffect, useState } from 'react';

/**
* `useMediaQuery` 커스텀 훅은 뷰포트의 크기를 감지하고, 주어진 쿼리와 일치하는지 확인합니다.
*
* @param {string} query - 미디어 쿼리 문자열입니다.
* @returns {boolean} 미디어 쿼리가 현재 뷰포트와 일치하는지 여부를 반환합니다.
*/
export const useMediaQuery = (query: string) => {
const [isMatch, setIsMatch] = useState(false);

useEffect(() => {
// If window is not defined, it means that the code is running on the server side.
if (typeof window === 'undefined') {
return;
}

const mediaQuery = window.matchMedia(query);
setIsMatch(mediaQuery.matches);

const listener = () => setIsMatch(mediaQuery.matches);

mediaQuery.addEventListener('change', listener);

return () => mediaQuery.removeEventListener('change', listener);
}, [query]);

return isMatch;
};
42 changes: 42 additions & 0 deletions packages/react/src/hooks/useSecTimer.en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# useSecTimer

`useSecTimer` is a custom React hook that provides a countdown timer functionality.
It allows you to set a timer that counts down from a specified number of seconds and provides functions to reset the timer and check if the timer has ended.

## Features

- Countdown Timer: Start a timer from a specified number of seconds and countdown to 0.
- Reset Functionality: Reset the timer to the initial value.
- Timer End Check: Easily check if the timer has reached 0.

## API

```ts
useSecTimer(seconds: number)
```

### Parameters

- `seconds` (number): The initial number of seconds for the countdown timer.

### Return value

- `leftTime` (number): The current time left on the timer in seconds.
- `isTimerEnd` (boolean): A boolean value that indicates whether the timer has reached 0.
- `resetTimer` (function): A function to reset the timer to the initial value.

## Examples

```jsx
const TimerComponent = () => {
const { leftTime, isTimerEnd, resetTimer } = useSecTimer(10);

return (
<div>
<div>Left time: {leftTime} seconds</div>
<div>Timer end: {isTimerEnd ? 'Yes' : 'No'}</div>
<button onClick={resetTimer}>Reset</button>
</div>
);
};
```
42 changes: 42 additions & 0 deletions packages/react/src/hooks/useSecTimer.ko.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# useSecTimer

`useSecTimer` 훅은 주어진 시간(초)에서 시작하여 0까지 카운트다운하는 타이머 기능을 제공합니다.
타이머를 초기화하고, 타이머 종료 여부를 확인할 수 있습니다.

## Features

- 카운트다운 타이머: 주어진 시간(초)에서 시작하여 0까지 카운트다운합니다.
- 리셋 기능: 타이머를 처음 값으로 초기화할 수 있습니다.
- 타이머 종료 확인: 타이머 종료 여부를 확인할 수 있습니다.

## API

```ts
useSecTimer(seconds: number)
```

### Parameters

- `seconds` (number): 카운트다운 타이머의 시간(초)입니다.

### Return value

- `leftTime` (number): 타이머에 남은 시간(초)입니다.
- `isTimerEnd` (boolean): 타이머가 0에 도달했는지 여부를 나타냅니다.
- `resetTimer` (function): 타이머를 처음 값으로 초기화하는 함수입니다.

## Examples

```jsx
const TimerComponent = () => {
const { leftTime, isTimerEnd, resetTimer } = useSecTimer(10);

return (
<div>
<div>Left time: {leftTime} seconds</div>
<div>Timer end: {isTimerEnd ? 'Yes' : 'No'}</div>
<button onClick={resetTimer}>Reset</button>
</div>
);
};
```
Loading

0 comments on commit 7f0fd57

Please sign in to comment.