일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- CSS
- React-Router-Dom
- 개발자를 위한 글쓰기 가이드
- framer-motion
- 테오의 스프린트
- 캐나다개발자
- 개발자 원칙
- SemVer
- 시스템디자인
- framer
- Semantic Versioning
- 코드트리
- 글또 10기
- Effective Typescript
- 이펙티브타입스크립트
- JSBridge
- typescript
- TS
- Framer motion
- ASP.NET
- 알고리즘
- 글또
- JUNCTION2023
- react
- 회고
- 캐나다취준
- CSS방법론
- 타입스크립트
- VS Code
- useState
- Today
- Total
큰 꿈은 파편이 크다!!⚡️
예제로 이해하는 React Custom Hook 본문
Building your own Hooks lets you extract component logic into reusable functions.
useState, useEffect, useMemo 등의 훅Hook은 리액트 16.8버전부터 추가되어 클래스를 작성하지 않고도 상태State관리를 편하게 할 수 있는 혁신적인 기능이었다.
그리고 재미있게도 나만의 커스텀 훅을 만드는 기능도 제공된다. 리액트 팀에서 훅을 만드는 원리대로 내 것을 만들 수 있다.
훅 또한 컴포넌트 등과 마찬가지로 함수이기 때문에 자바스크립트에서 함수를 분리할 때와 같이 분리하고, 컴포넌트에서 사용하고 싶은 값을 반환한다. 많이 사용되는 커스텀 예제들을 통해 어떤 식으로 사용할 수 있는지 알아보고, 익숙해져 보자!
🧐 고려할 것
· 재사용을 위해 분리한 함수이므로 unconditional 해야 한다
· use로 시작하는 컨벤션을 따른다
· 내부에서는 useState 등을 사용해서 자유롭게 만든다
예시. useWindowSize
브라우저 창 크기가 바뀔 때를 감지하여 사용할 수 있는 useWindowSize
커스텀 훅이다.
1. useState를 사용해서 window의 width, height를 관리한다
2. 최초 mount되었을 때 "resize" 이벤트 리스너를 추가한다. resize이벤트가 발생할때마다, useState로 설정한 window객체의 값을 갱신한다.
3. unmount될 때 resize이벤트를 제거한다.
export const useWindowSize = () => {
// Initialize state with undefined width/height so server and client renders match
// Learn more here: https://joshwcomeau.com/react/the-perils-of-rehydration/
const [windowSize, setWindowSize] = useState({
width: undefined,
height: undefined,
});
useEffect(() => {
// Handler to call on window resize
function handleResize() {
// Set window width/height to state
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
}
// Add event listener
window.addEventListener("resize", handleResize);
// Call handler right away so state gets updated with initial window size
handleResize();
// Remove event listener on cleanup
return () => window.removeEventListener("resize", handleResize);
}, []); // Empty array ensures that effect is only run on mount
return windowSize;
};
예시. useScroll
X, 또는 Y방향으로 Scroll 이벤트가 발생할때마다 Body Offset의 X, Y position을 나타내는데, scroll 이벤트이니만큼 debounce 등을 추가해서 더 효율적으로 개선할 수 있다.
코드의 흐름을 보면 위 useWindow 와 거의 동일함을 알 수 있다.
1. 필요한 변수들을 useState로 선언한다.
2. 최초 mount되었을 때 "scroll" 이벤트 리스너를 추가한다. scroll 이벤트가 발생할때마다, useState로 설정한 객체의 값을 갱신한다.
3. unmount될 때 scroll이벤트를 제거한다.
import { useState, useEffect } from "react";
export function useScroll() {
const [lastScrollTop, setLastScrollTop] = useState(0);
const [bodyOffset, setBodyOffset] = useState(
document.body.getBoundingClientRect()
);
const [scrollY, setScrollY] = useState(bodyOffset.top);
const [scrollX, setScrollX] = useState(bodyOffset.left);
const [scrollDirection, setScrollDirection] = useState();
const listener = e => {
setBodyOffset(document.body.getBoundingClientRect());
setScrollY(-bodyOffset.top);
setScrollX(bodyOffset.left);
setScrollDirection(lastScrollTop > -bodyOffset.top ? "down" : "up");
setLastScrollTop(-bodyOffset.top);
};
useEffect(() => {
window.addEventListener("scroll", listener);
return () => {
window.removeEventListener("scroll", listener);
};
});
return {
scrollY,
scrollX,
scrollDirection
};
}
사용
예시의 두 훅은 이렇게 사용한다.
☝️ 커스텀 훅을 통해서 인터랙티브한 페이지에서 자주 사용될 수 있는 이벤트들을 재사용하고,
✌️ 파일의 코드 라인 수도 줄일 수 있다.
· 브라우저 창 크기를 조절하면 변경된 크기의 width, height를 나타낸다.
· 스크롤 시 position을 나타낸다.
마무리
Custom Hook에 대해 정확하게 몰라서 기술부채라고 생각하고, 이번 글을 통해 다루어보았는데.. 생각보다 다룰 것이 없는 만큼 간단한 내용인 걸 알았다. 괜히 커스텀이라고 하니까 어려울 것이라 지레짐작하고 제대로 보지 않았던 나를 반성한다.🫥
원리를 아는 것과 응용은 별개의 문제겠지만 이제는 몰라서 안쓰는 게 아닌, 쓸 상황을 알고 사용 유무를 결정하겠다!
Reference
- https://reactjs.org/docs/hooks-custom.html
- https://react.vlpt.us/basic/21-custom-hook.html
- https://gist.github.com/joshuacerbito/ea318a6a7ca4336e9fadb9ae5bbb87f4
'Web FE' 카테고리의 다른 글
🔨 웹에서 RTSP 스트리밍 + video autoplay 삽질기 (0) | 2022.07.23 |
---|---|
🍪 쿠키와 세션 (feat. 웹에서 로그인을 유지하는 원리) (0) | 2022.07.09 |
Framer motion 순한맛 찍먹 (0) | 2022.05.29 |
react router dom6 적용하기 (0) | 2022.02.27 |
setState가 비동기인 이유? (0) | 2021.09.23 |