5. usehooks-ts

keyword

  • usehooks-ts

    • useBoolean

    • useEffectOnce

    • useFetch

    • useInterval

    • useEventListener

    • useLocalStorage

    • useDarkMode

  • swr

  • react-query

usehooks-ts

Custom Hook์„ ๋ชจ์•„๋†“์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ์ž˜ ๋งŒ๋“ค์–ด ๋†“์€ Custom Hook์„ ํ†ตํ•ด ์•„์ด๋””์–ด๋ฅผ ์–ป์–ด๊ฐ€์ž.

useBoolean

์ฐธ๊ณผ ๊ฑฐ์ง“์„ ํŒ๋ณ„ํ•˜๋Š” Hook, toggle๊ณผ ๊ฐ™์ด ์˜๋„๊ฐ€ ๋ช…ํ™•ํ•œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ž.

import { useBoolean } from 'usehooks-ts';

const { value : playing, toggle } = useBoolean();

const handleClick = () => toggle();

useEffectOnce

๋น„์–ด์žˆ๋Š” ์˜์กด์„ฑ ๋ฐฐ์—ด์„ ๋„ฃ์–ด ์ปดํฌ๋„ŒํŠธ ๋งˆ์šดํŠธ ์‹œ ๋”ฑ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰ํ•˜๋Š” effect, once์„ ๋ถ™์—ฌ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋จ์„ ๋ช…์‹œ์ ์œผ๋กœ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

import { useEffectOnce } from 'usehooks-ts';

  useEffectOnce(() => {
    const fetchProducts = async () => {
      const url = 'http://localhost:3000/products';
      const response = await fetch(url);
      const data = await response.json();
      setProducts(data.products);
    };

    fetchProducts();
  });

useFetch

์„œ๋ฒ„ API์— ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” Hook, ๊ฐ„๋‹จํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ๋•Œ ์œ ์šฉํ•˜๋‹ค.

import { useFetch } from 'usehooks-ts';

const url = 'http://localhost:3000/products';
const { data = {products: []} } = useFetch(url);

useInterval

setInterval์„ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•  ๋•Œ ์ฃผ์˜ํ•  ์ ์€ setInterval์˜ ์ฝœ๋ฐฑํ•จ์ˆ˜๋Š” ํด๋กœ์ €๋กœ์„œ ์™ธ๋ถ€ ๋ณ€์ˆ˜๋ฅผ ์ฐธ์กฐํ•œ๋‹ค. ๋–„๋ฌธ์— ํ•ด๋‹น ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์—ˆ์–ด๋„, ํ•จ์ˆ˜๊ฐ€ ์ •์˜๋  ๋‹น์‹œ์˜ ๊ฐ’์„ ๊ธฐ์–ตํ•˜๊ณ  ์žˆ์–ด ๋™์ผํ•œ ๊ฐ’์„ ์ฐธ์กฐํ•˜๊ฒŒ ๋œ๋‹ค.

function IntervalComponent() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      // setCount(count + 1); => X
      setCount(prevCount => prevCount + 1); 
    }, 1000);

    return () => {
      clearInterval(interval);
    };
  }, []);

  return <div>...</div>;
}

setInterval์„ ์‚ฌ์šฉํ•ด์•ผ ํ•  ๊ฒฝ์šฐ useInterval์„ ์‚ฌ์šฉํ•˜๊ณ , ์ง์ ‘ ๊ตฌํ˜„ ํ•ด์•ผํ•œ๋‹ค๋ฉด custom hook์„ ๋งŒ๋“ค์–ด ํ•ด๊ฒฐํ•ด์•ผํ•œ๋‹ค.

useInterval ์ฝ”๋“œ

import { useEffect, useLayoutEffect } from 'react'

export const useIsomorphicLayoutEffect =
  typeof window !== 'undefined' ? useLayoutEffect : useEffect

๋‚ด๋ถ€ ๋กœ์ง์— useIsomorphicLayoutEffect Hook์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๋ฐ ์‹คํ–‰ ํ™˜๊ฒฝ์ด ๋ธŒ๋ผ์šฐ์ €๋ฉด DOM ๋ Œ๋”๋ง ์ „์— ์‹คํ–‰๋˜๋Š” useLayoutEffect ํ›…์„ ์‚ฌ์šฉํ•˜๊ณ  ์•„๋‹ˆ๋ผ๋ฉด useEffect๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

useEventListener

window ๊ฐ์ฒด์— ์ ‘๊ทผํ•˜๋Š” ํ–‰์œ„๋„ ์™ธ๋ถ€ ์‹œ์Šคํ…œ๊ณผ ์‹ฑํฌํ•˜๋Š” ๋ถ€์ˆ˜ ํšจ๊ณผ์ด๋ฏ€๋กœ useEffect ๋‚ด๋ถ€์—์„œ ์กฐ์ž‘ํ•˜๋Š”๋ฐ useEventListener์˜ ์žฅ์ ์€ useEffect๋ฅผ ์ƒ๋žตํ•˜๊ณ  ๋ธŒ๋ผ์šฐ์ € ์Šคํฌ๋กค, ๋ฆฌ์‚ฌ์ด์ฆˆ ์ด๋ฒคํŠธ์™€ ๊ฐ™์ด window ๊ฐ์ฒด์— ์ ‘๊ทผํ•ด ๋ธŒ๋ผ์šฐ์ € ์ž์ฒด UI๋ฅผ ์กฐ์ž‘ํ•  ๋•Œ ์œ ์šฉํ•œ ๊ฒƒ ๊ฐ™๋‹ค. ํŠน์ˆ˜ํ•˜๊ฒŒ ์™ธ๋ถ€์— ๋ฌผ๋ ค์žˆ๋Š” ์ฝ”๋“œ๊ฐ€ ๋งŽ์„ ๊ฒฝ์šฐ ํ•ด๋‹น ํ›…์„ ์“ฐ๋ฉด ์œ ์šฉํ•˜๋‹ค๊ณ  ํ•œ๋‹ค.

useLocalStorage

์›น ์Šคํ† ๋ฆฌ์ง€, localStorage๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด๋ฅผ JSON์œผ๋กœ ์˜์†ํ™”(์™ธ๋ถ€์— ๋ฐ์ดํ„ฐ ์ €์žฅ์ด ์ง€์†๋˜๋Š”) ํ—ค๋‹น ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด ํŒ์—…์„ ๋ฉฐ์น ๊ฐ„ ์•ˆ๋ณด๊ธฐ, ํ…Œ๋งˆ ์ƒ‰์ƒ ๋ณ€๊ฒฝํ•˜๊ธฐ ๋“ฑ์ด ๊ฐ€๋Šฅ

useDarkMode

useDarkMode ๋‚ด๋ถ€์ ์œผ๋กœ useLocalStorage ํ›…์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Œ(๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ข…๋ฃŒ ํ›„ ์žฌ์‹คํ–‰ ๋์„ ๋•Œ ํ…Œ๋งˆ๋Š” ์ง€์†๋˜์–ด์•ผ ํ•จ)

์ข‹์€ ๊ธฐ๋Šฅ๋“ค์ด ๋งŽ์ด ์žˆ๋Š” ๊ฒƒ ๊ฐ™์€๋ฐ, ๊ฐœ์ธ์ ์œผ๋กœ๋Š” ๊ฐ€์ ธ๋‹ค ์“ฐ๊ธฐ๋งŒ ํ•˜๋ฉด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋„ˆ๋ฌด ์˜์กดํ•˜๊ฒŒ ๋˜๋‹ˆ ์ง์ ‘ ๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ•œ ๋ถ€๋ถ„์€ ์ตœ๋Œ€ํ•œ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.


swr


react-query

React Query๋Š” React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ๋ฅผ cachingํ•˜์—ฌ ํ•„์š”ํ•  ๋•Œ ๋‹ค์‹œ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

  • ์š”์ฒญ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ์บ์‹ฑํ•˜์—ฌ ๋™์ผํ•œ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ๋ฐ˜๋ณต์ ์ธ ์š”์ฒญ์„ ์บ์‹œ์—์„œ ์ œ๊ณตํ•จ (๋„คํŠธ์›Œํฌ ๋น„์šฉ ์ ˆ์•ฝ)

  • ๋ฐ์ดํ„ฐ ์š”์ฒญ ์‹คํŒจ์‹œ ์ž๋™ ์žฌ์‹œ๋„

์˜ˆ์ œ ์ฝ”๋“œ

import { useQuery } from '@tanstack/react-query';

function Products() {
  const { isLoading, error, data: products } = useQuery(['queryKey'], async () => {
    return fetch('request url').then((res) => res.json());
  })

  if (isLoading) return <p>Loading...</p>;

  if (error) return <p>{error}</p>;
}

์ฒซ๋ฒˆ์งธ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์š”์ฒญ ๋ฐ์ดํ„ฐ๋ฅผ queryKey์˜ ์ด๋ฆ„ ์•„๋ž˜์— ์š”์ฒญ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ์บ์‹ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‘๋ฒˆ์งธ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋˜‘๊ฐ™์€ queryKey๋กœ ๋„คํŠธ์›Œํฌ ํ†ต์‹  ์‹œ๋„ ์‹œ, ๋™์ผํ•œ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ๋ฐ˜๋ณต์ ์ธ ์š”์ฒญ์ด๋ฏ€๋กœ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ์บ์‹œ์—์„œ ์ œ๊ณตํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ์ค„์ธ๋‹ค. ์ฆ‰, A๋ผ๋Š” key๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ์š”์ฒญ์— ๋Œ€ํ•ด์„œ ๋™์ผํ•œ ์บ์‹œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

Last updated