본문 바로가기
Web Study/React 관련

노마드코더 React Hooks - 2

by 쿠리의일상 2023. 6. 13.

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

 

Notification - Web APIs | MDN

The Notification interface of the Notifications API is used to configure and display desktop notifications to the user.

developer.mozilla.org

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