๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

react

React / custom Hook

Custom Hook

์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ์ •์˜ํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” Hook์œผ๋กœ use๋กœ ์‹œ์ž‘ํ•˜๋Š” ์ด๋ฆ„์„ ์ง€์–ด์ฃผ๋ฉด ๋œ๋‹ค.

์ค‘๋ณต ๋˜๋Š” ๋ถ€๋ถ„์„ ํ›…์œผ๋กœ ๋งŒ๋“ค์–ด์„œ ์žฌ์‚ฌ์šฉ์„ฑ, ์œ ์ง€ ๋ณด์ˆ˜์„ฑ ๋ฐ ์ฝ”๋“œ ๊ฐ€๋…์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.

 


 

์˜ˆ์‹œ - Counter

 

+, - ๋ฒ„ํŠผ์œผ๋กœ ์ˆซ์ž๋ฅผ ์ฆ๊ฐ€ ๊ฐ์†Œ ์‹œํ‚ค๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•  ๋•Œ,

 

์ปค์Šคํ…€ ํ›…์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ (์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ)

  • UI์™€ ์ƒํƒœ๊ฐ€ ๊ฒฐํ•ฉ๋ผ ์žฌ์‚ฌ์šฉ์ด ์–ด๋ ค์›€ (App ์ปดํฌ๋„ŒํŠธ์˜ return๋ฌธ์—์„œ ์—ฌ๋Ÿฌ๋ฒˆ ๋ถˆ๋Ÿฌ์˜ค๋ฉด ์—ฌ๋Ÿฌ ๊ฐœ ์“ธ์ˆ˜๋Š” ์žˆ๋‹ค...)
  • ๋งŒ์•ฝ ๋˜‘๊ฐ™์€ ๋กœ์ง์„ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์—์„œ ์“ฐ๋ ค๋ฉด ๋ณต๋ถ™ํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผํ•จ
  • ์ปดํฌ๋„ŒํŠธ๋Š” ๋ณธ์งˆ์ ์œผ๋กœ๋Š” UI๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์กฐ๊ฐ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ฒ˜๋ฆฌ ๋กœ์ง, ์ƒํƒœ ๋“ฑ์ด ๋ณต์žกํ•ด์ง€๋ฉด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ณต์žกํ•ด์ง
function App() {
  return (
    <>
      <Counter />
    </>
  );
}

const Counter = () => {
  const [counter, setCounter] = useState(0);

  return (
    <>
      <div>counter : {counter}</div>
      <button onClick={() => setCounter((prev) => prev + 1)}>+</button>
      <button onClick={() => setCounter((prev) => prev - 1)}>-</button>
    </>
  );
};

 

 

์ปค์Šคํ…€ ํ›…์„ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ

์œ„ ์ฝ”๋“œ์™€ ๊ฐ™์€ ๊ธฐ๋Šฅ์—์„œ ์ฆ๊ฐํญ์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ๊นŒ์ง€ ์ถ”๊ฐ€ํ–ˆ๋‹ค. 

  • useCounter()๋ฅผ ํ˜ธ์ถœ๋งŒ ํ•˜๋ฉด ์–ด๋””์„œ๋“  ์ƒํƒœ๋ฅผ ๋˜‘๊ฐ™์ด ์“ธ ์ˆ˜ ์žˆ์–ด์„œ ์žฌ์‚ฌ์šฉ์„ฑ์ด ๋งค์šฐ ์ข‹์•„์ง
  • ๋…ผ๋ฆฌ๋ฅผ ๋ถ„๋ฆฌํ•ด์„œ ๊ด€๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•จ 
  • ์ปค์Šคํ…€ ํ›…์€ ๋ฐ˜๋ณต์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๋กœ์ง์„ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์ƒ์„ฑ
  • ์ธ์ž๋กœ ์„ค์ •์ด ๊ฐ€๋Šฅํ•ด(์•„๋ž˜ ์ฝ”๋“œ์—์„œ๋Š” ์ดˆ๊ธฐ๊ฐ’, step) ์œ ์—ฐ์„ฑ์ด ์ข‹์•„์ง 
function App() {
  // ์ดˆ๊ธฐ๊ฐ’์€ 0, step์€ 3์”ฉ ์ฆ/๊ฐ 
  // ๊ตฌ์กฐ๋ถ„ํ•ดํ• ๋‹น์œผ๋กœ ์„ธ ๊ฐ์ฒด๋ฅผ ๋ฐ›์•„์˜ด!
  const { count, increment, decrement } = useCounter(0, 3);

  return (
    <>
      <div>
        <div>custom Hook counter : {count}</div>
        <button onClick={increment}>+</button>
        <button onClick={decrement}>-</button>
      </div>
    </>
  );
}

// ์ปค์Šคํ…€ ํ›… ํ•จ์ˆ˜ ์ •์˜
// initialValue : ๊ธฐ๋ณธ๊ฐ’์€ 0, ์นด์šดํ„ฐ ์‹œ์ž‘ ์ˆซ์ž
// step : ๋ณ€ํ™” ํญ
const useCounter = (initialValue = 0, step) => {
  // count ์ƒํƒœ ์ƒ์„ฑ
  const [count, setcount] = useState(initialValue);
  // ๊ฐ๊ฐ ์ฆ๊ฐ€, ๊ฐ์†Œ ํ•จ์ˆ˜
  const increment = () => setcount((prev) => prev + step);
  const decrement = () => setcount((prev) => prev - step);
  // ์™ธ๋ถ€์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก count, increment, decrement๋ฅผ ๊ฐ์ฒด ํ˜•ํƒœ๋กœ ๋ฐ˜ํ™˜
  return { count, increment, decrement };
};

 

 

 

์˜ˆ์‹œ - ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ ๋ฐ›์•„์˜ค๊ธฐ

json-server๋ฅผ ์ด์šฉํ•ด ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ์—ฐ์Šต์ด๋‹ค.

์ด๋ฒˆ์—” db.json, db1.json, db2.json ํŒŒ์ผ ์„ธ๊ฐœ๋ฅผ ๋งŒ๋“ค์–ด์„œ ๊ฐ๊ฐ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด์คฌ๊ณ  ๋•Œ๋ฌธ์— ํฌํŠธ ๋ฒˆํ˜ธ๋„ 3000, 3001, 3002๋กœ ๋‹ค๋ฅด๊ฒŒ ์‹คํ–‰ํ–ˆ๋‹ค.

 

function App() {
  // error๋Š” ์“ฐ์ง€ ์•Š์œผ๋ฏ€๋กœ loading:loading1, data:data1 ์ด๋Ÿฐ์‹์œผ๋กœ ๊ตฌ์กฐ ๋ถ„ํ•ด ํ• ๋‹นํ•˜๋ฉด์„œ ๋ณ€์ˆ˜ ์ด๋ฆ„ ๋ฐ”๊พธ๊ธฐ๋„ ํ•ด์ค˜์•ผํ•จ
  const { loading: loading1, data: data1 } = useFetch(
    'http://localhost:3000/data',
  );
  const { loading: loading2, data: data2 } = useFetch(
    'http://localhost:3001/data',
  );
  const { loading: loading3, data: data3 } = useFetch(
    'http://localhost:3002/data',
  );

  return (
    <>
      {!loading1 && ( // ๋กœ๋”ฉ ์ค‘์ด ์•„๋‹ˆ๋ผ๋ฉด (loading1์ด false๋ผ๋ฉด)
        <ul>
          {data1.map((el) => (
            <li key={'data1' + el.id}>{el.content}</li>
          ))}
        </ul>
      )}
      {!loading2 && ( // ๋กœ๋”ฉ ์ค‘์ด ์•„๋‹ˆ๋ผ๋ฉด (loading2๊ฐ€ false๋ผ๋ฉด)
        <ul>
          {data2.map((el) => (
            <li key={'data1' + el.id}>{el.content}</li>
          ))}
        </ul>
      )}
      {!loading3 && ( // ๋กœ๋”ฉ ์ค‘์ด ์•„๋‹ˆ๋ผ๋ฉด (loading3์ด false๋ผ๋ฉด)
        <ul>
          {data3.map((el) => (
            <li key={'data1' + el.id}>{el.content}</li>
          ))}
        </ul>
      )}
    </>
  );
}

const useFetch = (url) => {
  // ๋กœ๋”ฉ ์ƒํƒœ ๊ด€๋ฆฌ
  const [loading, setLoading] = useState(true);
  // ๋ฐ์ดํ„ฐ์˜ ์ƒํƒœ ๊ด€๋ฆฌ
  const [data, setData] = useState(null);
  // ์—๋Ÿฌ ์ƒํƒœ ๊ด€๋ฆฌ
  const [error, setError] = useState(null);

  useEffect(() => {
    fetch(url)
      // json->javascript ๊ฐ์ฒด ํƒ€์ž…์œผ๋กœ ๋ณ€๊ฒฝํ•ด์„œ ๋ฐ›์•„์˜ด
      .then((res) => res.json())
      // ๋ฐ›์•„์˜จ ๋ฐ์ดํ„ฐ๋ฅผ setData๋กœ data ์—…๋ฐ์ดํŠธ
      .then((res) => {
        setData(res);
        setLoading(false);
      })
      // ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ
      .catch((err) => {
        setError(err);
        setLoading(false);
      });
    // ๋ฐ›์•„์˜ค๋Š” url์— ๋”ฐ๋ผ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ์˜์กด์„ฑ ๋ฐฐ์—ด์— url ์ถ”๊ฐ€
  }, [url]);

  // ๋กœ๋”ฉ ์ƒํƒœ, ๋ฐ์ดํ„ฐ, ์—๋Ÿฌ ์—ฌ๋ถ€๋ฅผ ๋ฐ˜ํ™˜
  return { loading, data, error };
};