-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: useEventListener ref 대응 추가 (#479)
- Loading branch information
Showing
8 changed files
with
153 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@modern-kit/react': patch | ||
--- | ||
|
||
fix: useEventListener ref 대응 추가 - @ssi02014 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
packages/react/src/hooks/useEventListener/useEventListener.utils.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { RefObject } from 'react'; | ||
|
||
/** | ||
* @description 이벤트 리스너를 연결할 수 있는 요소를 나타냅니다. | ||
*/ | ||
export type EventListenerAvailableElement = | ||
| Window | ||
| Document | ||
| HTMLElement | ||
| SVGElement | ||
| MediaQueryList; | ||
|
||
/** | ||
* @description `특정 유형`, `null`, `undefined`, `RefObject`가 될 수 있는 대상 요소입니다. | ||
*/ | ||
export type TargetElement<T extends EventListenerAvailableElement> = | ||
| T | ||
| null | ||
| undefined | ||
| RefObject<T | null | undefined>; | ||
|
||
/** | ||
* @description 주어진 요소가 `RefObject`인지 확인합니다. | ||
*/ | ||
export const isRefObject = <T extends EventListenerAvailableElement>( | ||
element: TargetElement<T> | ||
): element is RefObject<T | null | undefined> => { | ||
return !!(element as RefObject<T | null | undefined>)?.current; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,66 @@ | ||
import { useEffect, useRef, useState } from 'react'; | ||
|
||
import { usePreservedCallback } from '../usePreservedCallback'; | ||
import { useCallback, useRef, useState } from 'react'; | ||
import { noop } from '@modern-kit/utils'; | ||
import { useEventListener } from '../../hooks/useEventListener'; | ||
|
||
interface UseHoverProps { | ||
onEnter?: (event: MouseEvent) => void; | ||
onLeave?: (event: MouseEvent) => void; | ||
} | ||
|
||
interface UseHoverReturnType<T extends HTMLElement> { | ||
ref: React.RefObject<T>; | ||
isHovered: boolean; | ||
} | ||
|
||
/** | ||
* @description 대상 컴포넌트를 기준으로 마우스가 올라가거나 내려갔을 때의 상태를 반환하고, 마우스가 올라가거나 내려갔을 때의 액션을 정의할 수 있는 커스텀 훅입니다. | ||
* | ||
* @template T - HTML 엘리먼트 타입을 지정합니다. | ||
* @param {{ | ||
* onEnter?: (event: MouseEvent) => void; | ||
* onLeave?: (event: MouseEvent) => void; | ||
* }} props - 콜백 함수를 포함한 선택적 속성입니다. | ||
* - `onEnter`: 요소에 마우스가 진입할 때 호출되는 함수입니다. 기본값은 `noop` 함수입니다. | ||
* - `onLeave`: 요소에서 마우스가 떠날 때 호출되는 함수입니다. 기본값은 `noop` 함수입니다. | ||
* | ||
* @returns {UseHoverReturnType<T>} `ref`와 `isHovered`를 포함한 객체를 반환합니다. | ||
* - `ref`: 추적할 대상 요소의 참조입니다. | ||
* - `isHovered`: 요소가 호버 상태인지 여부를 나타내는 불리언 값입니다. | ||
* | ||
* @example | ||
* const { ref, isHovered } = useHover<HTMLDivElement>({ | ||
* onEnter: () => console.log('마우스 진입'), | ||
* onLeave: () => console.log('마우스 퇴장'), | ||
* }); | ||
* | ||
* return <div ref={ref}> {isHovered ? 'Hovered' : 'Not Hovered'} </div>; | ||
*/ | ||
export function useHover<T extends HTMLElement>({ | ||
onEnter = noop, | ||
onLeave = noop, | ||
}: UseHoverProps = {}) { | ||
}: UseHoverProps = {}): UseHoverReturnType<T> { | ||
const [isHovered, setIsHovered] = useState(false); | ||
|
||
const targetRef = useRef<T>(null); | ||
|
||
const onMouseEnter = usePreservedCallback((event: MouseEvent) => { | ||
setIsHovered(true); | ||
onEnter(event); | ||
}); | ||
|
||
const onMouseLeave = usePreservedCallback((event: MouseEvent) => { | ||
setIsHovered(false); | ||
onLeave(event); | ||
}); | ||
|
||
useEffect(() => { | ||
const targetElement = targetRef.current; | ||
if (!targetElement) return; | ||
const onMouseEnter = useCallback( | ||
(event: MouseEvent) => { | ||
setIsHovered(true); | ||
onEnter(event); | ||
}, | ||
[onEnter] | ||
); | ||
|
||
targetElement.addEventListener('mouseenter', onMouseEnter); | ||
targetElement.addEventListener('mouseleave', onMouseLeave); | ||
const onMouseLeave = useCallback( | ||
(event: MouseEvent) => { | ||
setIsHovered(false); | ||
onLeave(event); | ||
}, | ||
[onLeave] | ||
); | ||
|
||
return () => { | ||
targetElement.removeEventListener('mouseenter', onMouseEnter); | ||
targetElement.removeEventListener('mouseleave', onMouseLeave); | ||
}; | ||
}, [onMouseEnter, onMouseLeave]); | ||
useEventListener(targetRef, 'mouseenter', onMouseEnter); | ||
useEventListener(targetRef, 'mouseleave', onMouseLeave); | ||
|
||
return { ref: targetRef, isHovered }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters