TIL 31. React - Custom Hooks(2)

์‹ ๋ฏธ์˜ยท2021๋…„ 7์›” 9์ผ
0

React

๋ชฉ๋ก ๋ณด๊ธฐ
5/5

Custom Hooks... ๐Ÿ˜ตโ€ ... ๊ณต๋ถ€ํ•˜๋ฉด์„œ ์•Œ ๊ฒƒ ๊ฐ™์œผ๋ฉด์„œ๋„ ์–ด๋ ค์šด ๊ฒƒ ๊ฐ™๋‹ค.



๐ŸŽฏ useFadeIn

์‚ฌ์ดํŠธ์—์„œ ํŠน์ • ์š”์†Œ๊ฐ€ ๋‚˜ํƒ€๋‚˜๋Š” ํšจ๊ณผ๋ฅผ ์ฃผ๊ธฐ ์œ„ํ•œ Hooks์ด๋‹ค. ์œ ์‚ฌํ•œ ๋ฐฉ์‹์œผ๋กœ Fade Out Hooks๋„ ๋งŒ๋“ค์–ด ๋ณผ ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค.

const useFadeIn = (duration = 1, delay = 0) => {
  const element = useRef();
  // ํŽ˜์ด๋“œ์ธ ํšจ๊ณผ๋ฅผ ์ค„ ์š”์†Œ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด useRef๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

  useEffect(() => {
    const { current } = element;
    current.style.transition = `opacity ${duration}s ease-in-out ${delay}s`;
    current.style.opacity = 1;
  }, []);
  // duration(ํšจ๊ณผ ์ง„ํ–‰์‹œ๊ฐ„)๊ณผ delay(ํšจ๊ณผ ์ง€์—ฐ์‹œ๊ฐ„)์„ ์ธ์ž๋กœ ๋ฐ›๋Š”๋‹ค.
  // ์š”์†Œ์— ๋„ฃ์„ ํšจ๊ณผ๋ฅผ componentDidMount๋กœ ์ •์˜ํ•œ๋‹ค.
  
  return { ref: element, style: { opacity: 0 } };
  // ์š”์†Œ์— ์ธ๋ผ์ธ์œผ๋กœ ๋„ฃ์„ ์†์„ฑ์„ ๋ฆฌํ„ดํ•œ๋‹ค. 
  // opacity๋กœ ํŽ˜์ด๋“œ์ธ ํšจ๊ณผ๋ฅผ ์ฃผ๊ธฐ ์œ„ํ•ด ์ดˆ๊ธฐ๊ฐ’์œผ๋กœ opacity ๊ฐ’์„ 0์œผ๋กœ ์ค€๋‹ค.
};

// ์‚ฌ์šฉ ์˜ˆ์‹œ

const App = () => {
  const handleH = useFadeIn(2, 1);
  const handleP = useFadeIn(5, 3);
  return (
    <div>
      <h1 {...handleH}>Hello</h1>
      <p {...handleP}>welcome to my home!</p>
    </div>
  );
};


๐ŸŽฏ useNetwork

์‚ฌ์šฉ์ž๊ฐ€ ์ ‘์†ํ•œ ๋„คํŠธ์›Œํฌ ํ™˜๊ฒฝ์ด ์˜จ๋ผ์ธ์ธ์ง€ ์˜คํ”„๋ผ์ธ์ธ์ง€์— ๋”ฐ๋ผ ํŠน์ • ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” Hooks์ด๋‹ค.

const useNetwork = (onChange) => {
  const [status, setStatus] = useState(navigator.onLine);
  // ์˜จ๋ผ์ธ๊ณผ ์˜คํ”„๋ผ์ธ์ผ ๋•Œ์˜ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค.
  
  const handleNetwork = () => {
    if (typeof onChange === "function") {
      onChange(navigator.onLine);
    }
    setStatus(navigator.onLine);
  };

  useEffect(() => {
    window.addEventListener("online", handleNetwork);
    window.addEventListener("offline", handleNetwork);
    return () => {
      window.removeEventListener("online", handleNetwork);
      window.removeEventListener("offline", handleNetwork);
    };
  }, []);
  // ์ด๋ฒคํŠธ๋ฆฌ์Šค๋„ˆ๋กœ ์˜จ๋ผ์ธ๊ณผ ์˜คํ”„๋ผ์ธ์ผ ๋•Œ ๊ฐ๊ฐ ์ธ์ž๋กœ ๋„˜์–ด์˜ค๋Š” ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค. 

  return status;
};

// ์‚ฌ์šฉ ์˜ˆ์‹œ 

const App = () => {
  const checkStatus = (isOnline) => console.log(isOnline ? "yes" : "no");
  // useNetwork Hooks๋ฅผ ํ†ตํ•ด ์‹คํ–‰๋˜๋Š” ํ•จ์ˆ˜์ด๋‹ค.
  const onLine = useNetwork(checkStatus);

  return (
    <div>
      <h1>{onLine ? "Online" : "Offline"}</h1>
    // ์˜จ๋ผ์ธ, ์˜คํ”„๋ผ์ธ ์ƒํƒœ์— ๋”ฐ๋ผ ํ…์ŠคํŠธ๋ฅผ ๋…ธ์ถœํ•œ๋‹ค. 
    </div>
  );
};


๐ŸŽฏ useScroll

ํŽ˜์ด๋“œ์ธ/์•„์›ƒ๊ณผ ๋”๋ถˆ์–ด ์›น ํŽ˜์ด์ง€์—์„œ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ํšจ๊ณผ์ธ ์Šคํฌ๋กค ์ด๋ฒคํŠธ๋ฅผ Hooks๋กœ ๋งŒ๋“ค์—ˆ๋‹ค.

const useScroll = () => {
  const [scrollState, setScrollState] = useState({
    x: 0,
    y: 0
  });
  // ์ด๋ฒคํŠธ์˜ x, y์ขŒํ‘œ์˜ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜์—ฌ ์ด๋ฒคํŠธ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

  const handleScroll = () => {
    setScrollState({ x: window.scrollX, y: window.scrollY });
  };

  useEffect(() => {
    window.addEventListener("scroll", handleScroll);
    return () => {
      window.removeEventListener("scroll", handleScroll);
    };
  }, []);
  // ์Šคํฌ๋กค ์ด๋ฒคํŠธ๊ฐ€ ์žˆ์„ ๋•Œ๋งˆ๋‹ค ์ด๋ฒคํŠธ๊ฐ€ ์‹คํ–‰๋œ๋‹ค.

  return scrollState;
};

const App = () => {
  const { y } = useScroll();

  return (
    <div style={{ height: "1000vh" }}>
      <h1 style={{ position: "fixed", color: y > 100 ? "red" : "green" }}>
        // useScroll๋กœ ์ด๋ฒคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋Š” y ๊ฐ’์— ๋”ฐ๋ผ ์ปฌ๋Ÿฌ๊ฐ€ ๋ณ€๊ฒฝ๋œ๋‹ค. 
        Hello
      </h1>
    </div>
  );
};


๐ŸŽฏ useNotification

ํŠน์ • ์ด๋ฒคํŠธ์—์„œ ์•Œ๋ฆผ์ด ์˜ค๋„๋ก ํ•˜๋Š” Hooksd์ด๋‹ค. ์ด Hooks๋ฅผ ์—ฐ์Šตํ•˜๋ฉด์„œ MDN์ด ์–ผ๋งˆ๋‚˜ ์นœ์ ˆํ•œ์ง€ ๋‹ค์‹œ ํ•œ ๋ฒˆ ๋Š๊ผˆ๋‹ค. ๐Ÿ™‚

const useNotification = (title, options) => {
  if (!("Notification" in window)) {
    alert("This browser does not support desktop notification");
  }
  // ํ•ด๋‹น ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์•Œ๋ฆผ์„ ์ง€์›ํ•˜๊ณ  ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ๊ฐ€์žฅ ๋จผ์ € ํ™•์ธํ•œ๋‹ค.

  const getNotice = () => {
    if (Notification.permission === "granted") {
      new Notification(title, options);

      if (Notification.permission !== "denied") {
        Notification.requestPermission((permission) => {
          if (permission === "granted") {
            new Notification(title, options);
          }
        });
      }
    }
    // ์‚ฌ์šฉ์ž์˜ ์•Œ๋ฆผ ํ—ˆ์šฉ ์ƒํƒœ์— ๋งž์ถฐ ์•Œ๋ฆผ์„ ๋ณด๋‚ด๊ฑฐ๋‚˜ ์•Œ๋ฆผ ํ—ˆ์šฉ์„ ์š”์ฒญํ•œ๋‹ค.
  };

  return getNotice;
};

// ์‚ฌ์šฉ ์˜ˆ์‹œ

const App = () => {
  const handleNotice = useNotification("warning", { body: "JW loves you" });

  return (
    <div>
      <button onClick={handleNotice}>Click!</button>
    </div>
  );
};


๐ŸŽฏ useAxios

์œ„์ฝ”๋“œ์—์„œ ํ•œ ๋‹ฌ๊ฐ„ ์ง„ํ–‰ํ–ˆ๋˜ 2๋ฒˆ์˜ ํ”„๋กœ์ ํŠธ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›์œผ๋ฉฐ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์•˜๋Š”๋ฐ, ๊ทธ ๋•Œ๋งˆ๋‹ค ๋‚˜๋Š” fetch๋ฅผ ์‚ฌ์šฉํ–ˆ์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํ”„๋กœ์ ํŠธ ๋ฆฌํŒฉํ† ๋ง์—์„œ fetchํ–ˆ๋˜ ๋ถ€๋ถ„์„ axios๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด Axios๋ฅผ custom Hooks๋กœ ๋งŒ๋“ค์–ด ๋ณด์•˜๋‹ค!

axios ์„ค์น˜

npm i axios

App.js

import useAxios from './useAxios';


const App = () => {
  const { Loading, data, refetch } = useAxios({
    url: "https://yts.mx/api/v2/list_movies.json"
  });
  return (
    <div>
      <div>{Loading && "Loading..."}</div>
      <div>{data && data}</div>
      <button onClick={refetch}>Refetch!</button>
    </div>
  );
};

useAxios.js

import defaultAxios from "axios";
import { useState, useEffect } from "react";

const useAxios = (opts, axiosInstance = defaultAxios) => {
  const [state, setState] = useState({
    Loading: true,
    data: false,
    error: false
  });
  // ๋กœ๋”ฉ, ๋ฐ์ดํ„ฐ, ์—๋Ÿฌ ๊ฐ ์ƒํƒœ ์ดˆ๊ธฐ๊ฐ’์„ ์„ค์ •ํ•œ๋‹ค.

  const [trigger, setTrigger] = useState(0);

  const refetch = () => {
    setState({
      ...state,
      Loading: true
    });

    setTrigger(Date.now());
  };
  // re-fetch๋ฅผ ์œ„ํ•œ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ true๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.
  // useEffect๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•œ trigger์˜ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋„๋ก Date ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  
  useEffect(() => {
    axiosInstance(opts)
      .then((res) => setState({ ...state, Loading: false, data: res.status }))
      .catch((error) => {
        setState({ ...state, Loading: true, error: error });
      });
  }, [trigger]);
  // ์ธ์ž๋กœ ์ „๋‹ฌ๋ฐ›์€ url์— ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ณด์—ฌ์ค€๋‹ค. 
  // trigger๊ฐ€ ๋ณ€ํ™”๋  ๋•Œ๋งˆ๋‹ค ๋‹ค์‹œ fetch๋ฅผ ์ง„ํ–‰ํ•œ๋‹ค.

  return { ...state, refetch };
};

export default useAxios;

0๊ฐœ์˜ ๋Œ“๊ธ€

๊ด€๋ จ ์ฑ„์šฉ ์ •๋ณด