useEffect 를 활용한 커스텀 훅들
useEffect 란?
componentWillMount, componentDidMount, componentWillUpdate 의 클래스 컴포넌트의 생명주기 함수의 기능을 함수형 컴포넌트로 수행
useEffect(function, array);
첫번째 매개변수는 useEffect 이 실행될 때마다 실행될 콜백함수를 넣어준다.
두번째 매개변수는 의존성 배열 (deps) 로 해당 배열에 지정해준 그 값이 변경될 때마다 useEffect 를 실행시킬 수 있게 지정할 수 있다.
이미 알고 있는거지만 복습 겸 기초를 다진다 생각하고 다시 정리한다.
useEffect(콜백함수, []); // Mount 됐을 때 1번 실행
useEffect(콜백함수); // Mount와 Update 될 때마다 실행
useEffect(콜백함수, [item1, item2]); // Mount 됐을 때와 item1, item2가 변동될 때마다 실행
즉, dependency 배열이 중요함을 알 수 있음!
useTitle
const titleUpdater = useTitle('Loading...');
// 임시로 타이틀을 변경시켜주기
setTimeout(() => titleUpdater('Home'), 1500);
return (
<>
<h1>UseTitle</h1>
</>
)
const useTitle = (initTitle) => {
const [title, setTitle] = useState(initTitle);
const upadteTitle = () => {
const htmlTitle = document.querySelector('title');
htmlTitle.innerText = title;
}
useEffect(upadteTitle, [title]);
return setTitle;
}
title 태그를 찾아줘서 그 안의 innerText 를 변경시켜주는 커스텀 훅이다.
setTitle 을 변경해줄 때마다 실행된다.
useClick
기본 기능은 클릭 됐을 때 클릭 이벤트를 넣어주는 커스텀 훅이다.
이를 위해 useRef 를 활용, useRef 는 getElementXX 메서드와 동일한 기능을 하거나 리렌더링 되더라도 초기화되지 않는 저장된 값을 넣어서 연산할 때 등에 사용된다.
const useClick = (onClick) => {
const element = useRef();
useEffect(() => {
// Mount 될 때
if(element.current) {
element.current.addEventListener('click', onClick);
}
// return 해주는 부분은 UnMount 될 때 실행 -> 이벤트 핸들러를 없애준다.
return () => {
if(element.current) {
element.current.removeEventListener('click', onClick);
}
}
}, []);
return element;
}
useEffect 를 사용할 때 deps 배열에 아무것도 넣어주지 않으면 Mount 될때만 실행되고,
그때 return 값을 주면 UnMount 될 때 실행된다! 이 원리를 사용하여 이벤트 핸들러를 주고, 없애고 처리를 해준다.
const onClick = () => {
console.log('Hey!');
}
const title = useClick(onClick);
return (
<>
<h1 ref={title}>UseClick</h1>
</>
)
h1 의 ref 에 useClick 훅을 주었으므로 클릭할 때마다 Hey! 가 콘솔에 뜨게 된다.
useConfirm
사용자가 무언가를 할 때 브라우저에서 알려주는 알림창에 대한 커스텀 훅
const useConfirm = (message, onConfirm, onCancel) => {
if(!onConfirm || typeof onConfirm !== 'function') return;
if(onCancel && typeof onCancel !== 'function') return;
const confirmAction = () => {
if(window.confirm(message)) {
onConfirm(); // 찬성
} else {
onCancel(); // 반대
}
}
return confirmAction;
}
메세지와 콜백함수를 받아주고 메세지의 답에 따라 콜백을 실행할지 안할지 설정해주는 훅이다.
const deleteSomthing = () => console.log('Boom!');
const abortSomething = () => console.log('Thanks');
const confirmDelete = useConfirm('Are You sure?', deleteSomthing, abortSomething);
return (
<>
<h1>UseConfirm</h1>
<button onClick={confirmDelete}>Delete</button>
</>
)
usePreventLeave
윈도우 창을 닫을 때 글 같은 것을 쓰다가 닫게 되면 저장되지 않았는데 나가시겠습니까..? 이런 것들을 처리해주는 커스텀 훅
이벤트 핸들러 중 beforeunload 는 window 가 닫히기 전에 함수가 실행되는 것을 허락해주므로 위의 기능을 구현할 수 있다.
const usePreventLeave = () => {
const listener = (evt) => {
evt.preventDefault();
evt.preventValue = '';
}
const enablePrevent = () => window.addEventListener('beforeunload', listener);
const disablePrevent = () => window.removeEventListener('beforeunload', listener);
return { enablePrevent, disablePrevent };
}
const { enablePrevent, disablePrevent } = usePreventLeave();
return (
<>
<h1>UsePreventLeave</h1>
<button onClick={enablePrevent}>Protect</button>
<button onClick={disablePrevent}>UnProtect</button>
</>
)
useBeforeLeave
브라우저에서 벗어날 때마다 실행시켜주는 커스텀 훅
const useBeforeLeave = (onBefore) => {
const handle = () => {
console.log('Leaving');
}
useEffect(() => {
if(typeof onBefore !== 'function') return;
document.addEventListener('mouseleave', handle);
return () => document.removeEventListener('mouseleave', handle);
}, []);
}
document 이벤트 핸들러에 mouseleave 이벤트를 주어 해당 문서에서 벗어나고자 탭이나 다른 영역으로 이동하면 실행되는 이벤트이다.
아래의 경우 clientY 값을 조정하여 문서의 위쪽으로 갔을 때만 실행하게 할 수도 있다.
const useBeforeLeave = (onBefore) => {
const handle = (evt) => {
const { clientY } = evt;
if(clientY <= 0) // clientY의 값이 음수가 (위로 가게되면) 되면 실행됨
onBefore();
}
useEffect(() => {
if(typeof onBefore !== 'function') return;
document.addEventListener('mouseleave', handle);
return () => document.removeEventListener('mouseleave', handle);
}, []);
}
useFadeIn
페이드인 하는 컴포넌트를 만들기 위한 커스텀 훅
const useFadeIn = (duration = 1, delay = 0) => {
const element = useRef();
useEffect(() => {
if(typeof duration !== 'number' || typeof delay !== 'number') return;
if(element.current) {
const { current } = element;
current.style.transition = `opacity ${duration}s ease-in-out ${delay}s`;
current.style.opacity = 1;
}
}, []);
return {
ref : element,
style : { opacity : 0 },
};
}
const h1El = useFadeIn(3, 1);
const pEl = useFadeIn(2, 3);
return (
<>
<h1 {...h1El}>UseFadeIn</h1>
<p {...pEl}>Lorem ipsum dolor sit amet consectetur adipisicing elit. Est nulla qui incidunt, sequi aliquam illum reiciendis ex sapiente quia dignissimos nam vero tempora hic earum error obcaecati voluptatum minus totam.</p>
</>
)
useNetwork
네트워크가 online 또는 offline 이 되면 알려주는 커스텀 훅
navigator.onLine 으로 확인 가능
네트워크 탭에서 Offline 설정이 가능
const useNetwork = onChange => {
const [status, setStatus] = useState(navigator.onLine);
const handdleChange = () => {
if(typeof onChange === 'function')
onChange(navigator.onLine);
setStatus(navigator.onLine);
}
useEffect(() => {
window.addEventListener('online', handdleChange);
window.addEventListener('offline', handdleChange);
return () => {
window.removeEventListener('online', handdleChange);
window.removeEventListener('offline', handdleChange);
}
}, []);
return status;
}
const handleNetworkChange = (online) => {
console.log(online ? 'We just went online' : 'We are offline');
}
const onLine = useNetwork(handleNetworkChange);
return (
<>
<h1>{onLine ? 'Online' : 'Offline'}</h1>
</>
)
useScroll
유저가 스크롤하면서 일어나는 행동을 추가하기 좋은 커스텀 훅
const useScroll = () => {
const [state, setState] = useState({
x : 0,
y : 0,
});
const onScroll = () => {
setState({ x: window.scrollX, y: window.scrollY});
}
useEffect(() => {
window.addEventListener('scroll', onScroll);
return () => window.removeEventListener('scroll', onScroll);
}, []);
return state;
}
const { y } = useScroll();
return (
<div style={{
height: '100vw',
}}>
<h1 style={{ position: 'fixed', color : y > 100 ? 'red' : 'blue'}}>UseScroll</h1>
</div>
)
스크롤에 따라 색이 변함을 알 수 있다.
useFullscreen
requestFullscreen() 이라는 메서드를 활용하여 이미지를 전체화면으로 볼 수 있다.
해당 메서드를 사용하여 이미지를 전체화면화 해주는 커스텀 훅이다.
const useFullScreen = () => {
const element = useRef();
const triggerFullscreen = () => {
if(element.current) {
element.current.requestFullscreen();
}
}
const exitFullscreen = () => {
if(document.fullscreenElement)
document.exitFullscreen();
}
return {element, triggerFullscreen, exitFullscreen};
}
document.fullscreenElement 로 풀 스크린인지 확인한 뒤에 document.exitFullscreen() 메서드로 전체화면을 나와줄 수 있는 버튼을 생성 가능하다.
const {element, triggerFullscreen, exitFullscreen} = useFullScreen();
return (
<>
<h1>UseFullScreen</h1>
<div ref={element}>
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcT5r_mJJ8ATBIuev-xk0VPbH0jTT_KyzquN_8Tdifa2E-i8D1zs9-uht_qiJOFg9hEZy4A&usqp=CAU" alt="강아지" />
<button onClick={exitFullscreen}>Exit Fullscreen</button>
</div>
<button onClick={triggerFullscreen}>Make Fullscreen</button>
</>
)
useNotification
알람이 실행되는 커스텀 훅, notification API 를 사용해준다.
https://developer.mozilla.org/en-US/docs/Web/API/Notification
const useNotification = (title, options) => {
if(!("Notification" in window)) return;
const fireNotif = () => {
if(Notification.permission !== 'granted') {
Notification.requestPermission().then(permission => {
if(permission === 'granted') {
new Notification(title, options);
} else {
return;
}
});
} else {
new Notification(title, options);
}
}
return fireNotif;
}
Notification API 를 사용하기 위해선 일단 브라우저에서 지원이 되는지 window 로 확인하고,
Notificatino.permission 값은 denied granted default 가 될 수 있어서 granted 가 아닐 땐
requestPermission() 메서드를 사용하여 알람을 보내도 되는지 확인할 수 있고, 또다시 granted 가 되면 new 로 인스턴스를 만들어준다.
const triggerNotification = useNotification('Alarm!!', {
body : '알람?!',
});
return (
<>
<h1>UseNotification</h1>
<button onClick={triggerNotification}>Trigger!</button>
</>
)
options 부분의 body 로 내용 부분을 채워줄 수 있다.
혹여 알람이 안온다면 맥의 경우, 설정 > 알림 > 브라우저의 알림이 꺼져있는지 확인할 것.
useAxios
데이터 fetching 에 사용하는 커스텀훅
import defaultAxios from 'axios';
const useAxios = (options, axiosInstance = defaultAxios) => {
const [state, setState] = useState({
loading: true,
error: null,
data: null,
});
const [trigger, setTrigger] = useState(0);
const refetch = () => {
setState({
...state,
loading : true,
});
setTrigger(Date.now());
}
useEffect(() => {
if(!options.url) return;
axiosInstance(options).then(data => {
setState({
...state,
loading : false,
data,
});
}).catch(error => {
setState({
...state,
loading : false,
error,
});
});
}, [trigger]);
return {...state, refetch};
}
const { loading, error, data, refetch } = useAxios({
url : 'https://yts.mx/api/v2/list_movies.json',
})
console.log(loading, error);
console.log(JSON.stringify(data));
return (
<>
<h1>UseAxios</h1>
<p>{data && data.status}</p>
<p>{loading && 'loading'}</p>
<button onClick={refetch}>Refetch!</button>
</>
)
커스텀 훅을 npm 에 올리기!
dependencies 를 peerDependencies 로 변경한다. (있으면 굳이 필요하지 않다는 의미?)
npm publish --access publish
해주면 npm 에 올라가게 되고 npm으로 다운 받아서 사용해주면 된다.
'Web Study > React 관련' 카테고리의 다른 글
Vite - 플러그인 사용하기 (0) | 2023.06.19 |
---|---|
CRA 와 Vite (0) | 2023.06.19 |
노마드코더 React Hooks - 1 (0) | 2023.06.11 |
React 로 Netlify 배포 해보기.. feat.Heroku (0) | 2023.05.23 |
React 프로젝트 Netlify 에 배포하기 (1) | 2023.05.16 |