๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
JavaScript/React

[React] Hooks ์ •๋ฆฌ

by soy๋ฏธ๋‹ˆ 2021. 10. 26.

 

 

 

๐Ÿ’ก useState

// useState ํ•จ์ˆ˜ ์‚ฌ์šฉํ•˜๊ธฐ
import { useState } from "react";

const Counter = () => {
  const [value, setValue] = useState(0); 
  return (
    <div>
      <p>ํ˜„์žฌ ์นด์šดํ„ฐ ๊ฐ’์€ {value} ์ด๋‹ค.</p>
      <button onClick={() => setValue(value + 1)}>+1</button>
      <button onClick={() => setValue(value - 1)}>-1</button>
    </div>
  );
};
export default Counter;

 

 

  • useState ๋Š” ํ•˜๋‚˜์˜ ์ƒํƒœ ๊ฐ’๋งŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์œผ๋‚˜ ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ด€๋ฆฌํ•ด์•ผ ํ•  ์ƒํƒœ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ๋ผ๋ฉด useState ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.
  • useState(0) ์ด๋ž€ ์ดˆ๊ธฐ๊ฐ’์„ 0 ์œผ๋กœ ํ•˜๊ฒ ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.
  • const [value, setValue] ์—์„œ ์ฒซ ๋ฒˆ์งธ ์›์†Œ์ธ value ๋Š” ์ƒํƒœ ๊ฐ’, ๋‘ ๋ฒˆ์งธ ์›์†Œ์ธ setValue ๋Š” ์ƒํƒœ๋ฅผ ์„ค์ •ํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค.
  • ์ด ํ•จ์ˆ˜์— ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋„ฃ์–ด์„œ ํ˜ธ์ถœํ•˜๋ฉด(setValue(value+1) ๊ณผ ๊ฐ™์ด) ์ „๋‹ฌ๋ฐ›์€ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๊ฐ’์ด ๋ฐ”๋€Œ๊ณ  ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋ฆฌ๋ Œ๋”๋งํ•œ๋‹ค.

 

 

์›น ์‹คํ–‰ ํ™”๋ฉด

 

 

 

useState ์—ฌ๋Ÿฌ ๋ฒˆ ์‚ฌ์šฉํ•˜๊ธฐ

 

import { useState } from "react";

const Info = () => {
  const [name, setName] = useState("");
  const [nickname, setNickname] = useState("");

  const onChangeName = (e) => {
    setName(e.target.value);
  };

  const onChangeNickName = (e) => {
    setNickname(e.target.value);
  };

  return (
    <div>
      <input value={name} onChange={onChangeName} />
      <input value={nickname} onChange={onChangeNickName} />
      <div>์ด๋ฆ„ : {name}</div>
      <div>๋‹‰๋„ค์ž„ : {nickname}</div>
    </div>
  );
};

export default Info;

 

 

 

์›น ์‹คํ–‰ ํ™”๋ฉด

 

 

 

 

๐Ÿ’ก useEffect

๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง ๋  ๋•Œ๋งˆ๋‹ค ํŠน์ • ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” Hook ์ด๋‹ค. useEffect ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ Œ๋”๋ง๋˜๊ณ  ๋‚œ ์งํ›„๋งˆ๋‹ค ์‹คํ–‰๋˜๋ฉฐ, ๋‘ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐฐ์—ด์— ๋ฌด์—‡์„ ๋„ฃ๋Š”์ง€์— ๋”ฐ๋ผ ์‹คํ–‰๋˜๋Š” ์กฐ๊ฑด์ด ๋‹ฌ๋ผ์ง„๋‹ค. ํด๋ž˜์Šค ํ˜• ์ปดํฌ๋„ŒํŠธ์ธ componentDidMount ์™€ componentDidUpdate ๋ฅผ ํ•ฉ์นœ ํ˜•ํƒœ๋กœ ๋ณด์•„๋„ ๋ฌด๋ฐฉํ•˜๋‹ค.

 

import { useState, useEffect } from "react";

const Info = () => {
  const [name, setName] = useState("");
  const [nickname, setNickname] = useState("");

  useEffect(() => {
    console.log("๋ Œ๋”๋ง์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
    console.log({
      nickname,
    });
  }, [nickname]);

  const onChangeName = (e) => {
    setName(e.target.value);
  };

  const onChangeNickName = (e) => {
    setNickname(e.target.value);
  };

  return (
    <div>
      <input value={name} onChange={onChangeName} />
      <input value={nickname} onChange={onChangeNickName} />
      <div>์ด๋ฆ„ : {name}</div>
      <div>๋‹‰๋„ค์ž„ : {nickname}</div>
    </div>
  );
};

export default Info;

 

useEffect ๋ฅผ ํŠน์ • ๊ฐ’์ด ์—…๋ฐ์ดํŠธ ๋  ๋•Œ๋งŒ ํ˜ธ์ถœํ•˜๊ณ  ์‹ถ์œผ๋ฉด, useEffect ์˜ ๋‘ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌ๋˜๋Š” ๋ฐฐ์—ด [ ] ์•ˆ์— ๊ฒ€์‚ฌํ•˜๊ณ  ์‹ถ์€ ๊ฐ’์„ ๋„ฃ์–ด ์ฃผ๋ฉด ๋œ๋‹ค.

 

  useEffect(() => {
    console.log("๋ Œ๋”๋ง์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
    console.log({
      nickname,
    });
  }, [nickname]);

 

 

๊ฒ€์‚ฌํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฐ’์„ nickname ์œผ๋กœ ์„ค์ •ํ–ˆ๋”๋‹ˆ nickname ์ด ๋ฐ”๋€” ๋•Œ๋งŒ useEffect ์˜ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ฐ”๋€Œ์—ˆ๋‹ค.

 

 

 

 

์›น ์‹คํ–‰ ํ™”๋ฉด

 

 

 

 

 

 

useEffect  ๋’ท์ •๋ฆฌ ํ•˜๊ธฐ

์ปดํฌ๋„ŒํŠธ๊ฐ€ ์–ธ๋งˆ์šดํŠธ๋˜๊ธฐ ์ „์ด๋‚˜ ์—…๋ฐ์ดํŠธ ๋˜๊ธฐ ์ง์ „์— ์–ด๋– ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์‹ถ์œผ๋ฉด useEffect ์—์„œ ๋’ท์ •๋ฆฌ(clean up) ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

 

// App.js
import React, { useState } from "react";
import Info from "./Info";
const App = () => {
  const [visible, setVisible] = useState(false);
  return (
    <div>
      <button
        onClick={() => {
          setVisible(!visible);
          console.log(!visible);
        }}
      >
        {visible ? "์ˆจ๊ธฐ๊ธฐ" : "๋ณด์ด๊ธฐ"}
      </button>
      <hr />
      {visible && <Info />}
    </div>
  );
};
export default App;

 

// Info.js
import { useState, useEffect } from "react";
const Info = () => {
  const [name, setName] = useState("");
  const [nickname, setNickname] = useState("");
  useEffect(() => {
    console.log("effect");
    return () => { // cleanup ํ•จ์ˆ˜ ๋ฐ˜ํ™˜
      console.log("unmount");
    };
  }, []);
  const onChangeName = (e) => {
    setName(e.target.value);
  };
  const onChangeNickName = (e) => {
    setNickname(e.target.value);
  };
  return (
    <div>
      <input value={name} onChange={onChangeName} />
      <input value={nickname} onChange={onChangeNickName} />
      <div>์ด๋ฆ„ : {name}</div>
      <div>๋‹‰๋„ค์ž„ : {nickname}</div>
    </div>
  );
};
export default Info;

 

๋ Œ๋”๋ง ๋  ๋•Œ๋งˆ๋‹ค ๋’ท์ •๋ฆฌ ํ•จ์ˆ˜๊ฐ€ ๊ณ„์† ๋‚˜ํƒ€๋‚˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ๋’ท์ •๋ฆฌ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ๋Š” ์—…๋ฐ์ดํŠธ ๋˜๊ธฐ ์ง์ „์˜ ๊ฐ’์„ ๋ณด์—ฌ์ค€๋‹ค. ์–ธ๋งˆ์šดํŠธ(์ปดํฌ๋„ŒํŠธ๊ฐ€ DOM ์—์„œ ์ œ๊ฑฐ๋˜๋Š” ๊ฒƒ, ์—ฌ๊ธฐ์„œ๋Š” ์ˆจ๊ธฐ๊ธฐ ๋ฒ„ํŠผ ๋ˆ„๋ฅผ ๋•Œ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.) ๋  ๋•Œ๋งŒ ๋’ท์ •๋ฆฌ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ์‹ถ์œผ๋ฉด useEffect ํ•จ์ˆ˜์˜ ๋‘ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ์— ๋น„์–ด ์žˆ๋Š” ๋ฐฐ์—ด์„ ๋„ฃ์œผ๋ฉด ๋œ๋‹ค.

 

 

 

 

์›น ์‹คํ–‰ ํ™”๋ฉด

 

 

 

 

 

 

 

 

 

๐Ÿ’ก useReducer

useReducer ๋Š” useState ๋ณด๋‹ค ๋” ๋‹ค์–‘ํ•œ ์ปดํฌ๋„ŒํŠธ ์ƒํ™ฉ์— ๋”ฐ๋ผ ๋‹ค์–‘ํ•œ ์ƒํƒœ๋ฅผ ๋‹ค๋ฅธ ๊ฐ’์œผ๋กœ ์—…๋ฐ์ดํŠธ ํ•ด์ฃผ๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” Hook ์ด๋‹ค. Reducer ๋Š” ํ˜„์žฌ ์ƒํƒœ(state), ๊ทธ๋ฆฌ๊ณ  ์—…๋ฐ์ดํŠธ๋ฅผ ์œ„ํ•ด ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ๋‹ด์€ action ๊ฐ’์„ ์ „๋‹ฌ๋ฐ›์•„ ์ƒˆ๋กœ์šด ์ƒํƒœ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค. useReducer ์—์„œ action ์€ ๊ทธ ์–ด๋–ค ๊ฐ’๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ, reducer ํ•จ์ˆ˜์—์„œ ์ƒˆ๋กœ์šด ์ƒํƒœ๋ฅผ ๋งŒ๋“ค ๋•Œ๋Š” ๋ฐ˜๋“œ์‹œ ๋ถˆ๋ณ€์„ฑ์„ ์ง€์ผœ ์ฃผ์–ด์•ผ ํ•œ๋‹ค.

 

 

// useReducer ์‚ฌ์šฉํ•˜๊ธฐ

import { useReducer } from "react";
function reducer(state, action) {
  switch (action.type) {
    case "INCREMENT":
      return { value: state.value + 1 };
    case "DECREMENT":
      return { value: state.value - 1 };
    default:
      return state;
  }
}

const Counter = () => {
  const [state, dispatch] = useReducer(reducer, { value: 0 });

  return (
    <div>
      <p>
        ํ˜„์žฌ ์นด์šดํ„ฐ ๊ฐ’์€ <b>{state.value}</b>์ž…๋‹ˆ๋‹ค.
      </p>
      <button onClick={() => dispatch({ type: "INCREMENT" })}>+1</button>
      <button onClick={() => dispatch({ type: "DECREMENT" })}>-1</button>
    </div>
  );
};
export default Counter;

 

useReducer ์˜ ์ฒซ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ์—๋Š” reducer ํ•จ์ˆ˜๋ฅผ ๋„ฃ๊ณ , ๋‘ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ์—๋Š” ํ•ด๋‹น reducer ์˜ ๊ธฐ๋ณธ๊ฐ’ {value: 0} ์„ ๋„ฃ์–ด์ค€๋‹ค. ์ด Hook ์„ ์‚ฌ์šฉํ•˜๋ฉด state ๊ฐ’๊ณผ dispatch ํ•จ์ˆ˜๋ฅผ ๋ฐ›์•„ ์˜จ๋‹ค. ์—ฌ๊ธฐ์„œ state ๋Š” ํ˜„์žฌ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๋Š” ์ƒํƒœ๊ณ , dispatch ๋Š” ์•ก์…˜์„ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ํ•จ์ˆ˜์ด๋‹ค. dispatch(action) ๊ณผ ๊ฐ™์€ ํ˜•ํƒœ๋กœ, ํ•จ์ˆ˜ ์•ˆ์— ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ action ๊ฐ’์„ ๋„ฃ์–ด์ฃผ๋ฉด reducer ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๊ตฌ์กฐ์ด๋‹ค. 

 

 

 

// Info.js
import { useReducer } from "react";
function reducer(state, action) {
  return {
    ...state,  // useReducer ๋กœ๋ถ€ํ„ฐ ์ „๋‹ฌ๋ฐ›์€ state ๊ฐ’ (name:'', nickname:'') ๋ณต์‚ฌ
    [action.name]: action.value, // action.name ์€ e.target.name (input ์˜ name) ์ด๋ฉฐ action.value ๋Š” e.target.value (input ์˜ value) ์ธ ๊ฒƒ์ด๋‹ค.
  };
}

const Info = () => {
  const [state, dispatch] = useReducer(reducer, {
    name: "",  // reducer ์— ...state ๊ฐ’์œผ๋กœ ์ „๋‹ฌํ•˜๊ธฐ
    nickname: "",
  });
  const { name, nickname } = state; // state ๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” name, nickname ๊ฐ’์„ name, nickname ํ•„๋“œ์— ๋„ฃ์–ด์ค€๋‹ค.

  const onChange = (e) => {
    dispatch(e.target); // action ์€ e.target
    console.log(e.target);
  };

  return (
    <div>
      <input name="name" value={name} onChange={onChange} />
      <input name="nickname" value={nickname} onChange={onChange} />
      <div>์ด๋ฆ„ : {name}</div>
      <div>๋‹‰๋„ค์ž„ : {nickname}</div>
    </div>
  );
};

export default Info;

 

 

dispatch(e.target) ์œผ๋กœ ์—ฌ๊ธฐ์„œ dispatch ๊ฐ€ ์ „๋‹ฌํ•˜๋Š” action ์€ e.target ์ด๋‹ค. ์ฆ‰, action.name ์€ e.target.name ์ด๊ณ  ์ด๊ฒƒ์€ input ์š”์†Œ์˜ name ์†์„ฑ์„ ๋งํ•œ๋‹ค. action.value ๋Š” e.target.value ์ด๊ณ  ์ด๊ฒƒ์€ input ์š”์†Œ์˜ value ์†์„ฑ์„ ๋งํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์œ„์˜ input ์š”์†Œ์— name="name" ๋ฐ name="nickname" ์„ ๋ช…์‹œํ•ด์ฃผ์ง€ ์•Š์œผ๋ฉด input ์— ๊ฐ’ ์ž…๋ ฅ์ด ๋ถˆ๊ฐ€ํ•˜๊ณ , ์‹คํ–‰์ด ์ œ๋Œ€๋กœ ๋˜์ง€ ์•Š๋Š”๋‹ค.

 

 

 

 

 

์›น ์‹คํ–‰ ํ™”๋ฉด

 

 

 

 

 

 

๐Ÿ’ก useMemo

useMemo ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์—ฐ์‚ฐ์„ ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

// Average.js
import { useState, useMemo } from "react";
const getAverage = (numbers) => {
  console.log("ํ‰๊ท ๊ฐ’ ๊ณ„์‚ฐ ์ค‘..");
  console.log(numbers);
  if (numbers.length === 0) return 0;
  const sum = numbers.reduce((a, b) => a + b);
  return sum / numbers.length;
};

const Average = () => {
  const [list, setList] = useState([]);
  const [number, setNumber] = useState("");

  const onChange = (e) => {
    setNumber(e.target.value);
  };

  const onInsert = () => {
    const nextList = list.concat(parseInt(number));
    setList(nextList);
    setNumber("");
  };

  // ํŠน์ • ๊ฐ’์ด ๋ฐ”๋€Œ์—ˆ์„ ๋•Œ๋งŒ ์—ฐ์‚ฐ์„ ์‹คํ–‰ํ•˜๊ณ  ์›ํ•˜๋Š” ๊ฐ’์ด ๋ฐ”๋€Œ์ง€ ์•Š์•˜๋‹ค๋ฉด ์ด์ „์— ์—ฐ์‚ฐํ–ˆ๋˜ ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์‹œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹
  const avg = useMemo(() => getAverage(list), [list]);

  return (
    <div>
      <input value={number} onChange={onChange} />
      <button onClick={onInsert}>๋“ฑ๋ก</button>
      <ul>
        {list.map((value, index) => (
          <li key={index}>{value}</li>
        ))}
      </ul>
      {/* list ๋Š” value ๋งŒ ๋‹ด๊ธด ๋ฆฌ์ŠคํŠธ๋กœ ๋จ. */}
      <div>
        <b>ํ‰๊ท ๊ฐ’: </b> {avg}
      </div>
    </div>
  );
};

export default Average;

 

  const avg = useMemo(() => getAverage(list), [list]);

 

useMemo ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ Œ๋”๋ง ํ•˜๋Š” ๊ณผ์ •์—์„œ ํŠน์ • ๊ฐ’์ด ๋ฐ”๋€Œ์—ˆ์„ ๋•Œ๋งŒ ์—ฐ์‚ฐ์„ ์‹คํ–‰ํ•˜๊ณ  ์›ํ•˜๋Š” ๊ฐ’์ด ๋ฐ”๋€Œ์ง€ ์•Š์•˜๋‹ค๋ฉด ์ด์ „์— ์—ฐ์‚ฐํ–ˆ๋˜ ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์‹œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. ์œ„์˜ ์ฝ”๋“œ์—์„œ๋Š” list ์˜ ๊ฐ’์ด ๋ฐ”๋€Œ์—ˆ์„ ๋•Œ๋งŒ ์—ฐ์‚ฐ์„ ์‹คํ–‰ํ•˜๋„๋ก ๋‘ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ list ๋กœ ๋‘์–ด ๋ Œ๋”๋ง ํ•  ๋•Œ๋งˆ๋‹ค ๊ฒ€์‚ฌํ•˜๋„๋ก ํ–ˆ๋‹ค.

 

 

<ul>
   {list.map((value, index) => (
   <li key={index}>{value}</li>
    ))}
</ul>

 

list.map ์œผ๋กœ ์ธํ•ด value ์™€ index ์— ๋”ฐ๋ผ <li> ํƒœ๊ทธ๋กœ ๋ฌถ์—ฌ์ง€๊ณ  list ๋กœ ๋ฌถ์—ฌ์ ธ ๋‚˜์˜จ๋‹ค.

 

 

 

 

 

๐Ÿ’ก useCallback

// useCallback
import { useState, useMemo, useCallback } from "react";
const getAverage = (numbers) => {
  console.log("ํ‰๊ท ๊ฐ’ ๊ณ„์‚ฐ ์ค‘..");
  console.log(numbers);
  if (numbers.length === 0) return 0;
  const sum = numbers.reduce((a, b) => a + b);
  return sum / numbers.length;
};

const Average = () => {
  const [list, setList] = useState([]);
  const [number, setNumber] = useState("");

  const onChange = useCallback((e) => {
    setNumber(e.target.value);
  }, []);              // ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ฒ˜์Œ ๋ Œ๋”๋ง๋  ๋•Œ๋งŒ ํ•จ์ˆ˜ ์ƒ์„ฑ

  const onInsert = useCallback(() => {
    const nextList = list.concat(parseInt(number));
    setList(nextList);
    setNumber("");
  }, [number, list]);  // number ํ˜น์€ list ๊ฐ€ ๋ฐ”๋€Œ์—ˆ์„ ๋•Œ๋งŒ ํ•จ์ˆ˜ ์ƒ์„ฑ

  // ํŠน์ • ๊ฐ’์ด ๋ฐ”๋€Œ์—ˆ์„ ๋•Œ๋งŒ ์—ฐ์‚ฐ์„ ์‹คํ–‰ํ•˜๊ณ  ์›ํ•˜๋Š” ๊ฐ’์ด ๋ฐ”๋€Œ์ง€ ์•Š์•˜๋‹ค๋ฉด ์ด์ „์— ์—ฐ์‚ฐํ–ˆ๋˜ ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์‹œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹
  const avg = useMemo(() => getAverage(list), [list]);

  return (
    <div>
      <input value={number} onChange={onChange} />
      <button onClick={onInsert}>๋“ฑ๋ก</button>
      <ul>
        {list.map((value, index) => (
          <li key={index}>{value}</li>
        ))}
      </ul>
      {/* list ๋Š” value ๋งŒ ๋‹ด๊ธด ๋ฆฌ์ŠคํŠธ๋กœ ๋จ. */}
      <div>
        <b>ํ‰๊ท ๊ฐ’: </b> {avg}
      </div>
    </div>
  );
};

export default Average;

 

useCallback ์˜ ์ฒซ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ์—๋Š” ์ƒ์„ฑํ•˜๊ณ  ์‹ถ์€ ํ•จ์ˆ˜๋ฅผ ๋„ฃ๊ณ , ๋‘ ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ์—๋Š” ๋ฐฐ์—ด์„ ๋„ฃ์œผ๋ฉด ๋œ๋‹ค. ์ด ๋ฐฐ์—ด์—๋Š” ์–ด๋–ค ๊ฐ’์ด ๋ฐ”๋€Œ์—ˆ์„ ๋•Œ ํ•จ์ˆ˜๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•ด์•ผ ํ•˜๋Š”์ง€ ๋ช…์‹œํ•ด์•ผ ํ•œ๋‹ค. onChange ์ฒ˜๋Ÿผ ๋น„์–ด ์žˆ๋Š” ๋ฐฐ์—ด์„ ๋„ฃ๊ฒŒ ๋˜๋ฉด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง ๋  ๋•Œ ๋งŒ๋“ค์—ˆ๋˜ ํ•จ์ˆ˜๋ฅผ ๊ณ„์†ํ•ด์„œ ์žฌ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉฐ onInsert ์ฒ˜๋Ÿผ ๋ฐฐ์—ด ์•ˆ์— number ์™€ list ๋ฅผ ๋„ฃ๊ฒŒ ๋˜๋ฉด input ๋‚ด์šฉ์ด ๋ฐ”๋€Œ๊ฑฐ๋‚˜ ์ƒˆ๋กœ์šด ํ•ญ๋ชฉ์ด ์ถ”๊ฐ€๋  ๋•Œ ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์ง„ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋œ๋‹ค.

 

 

 

 

 

๐Ÿ’ก useRef

ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ ref ๋ฅผ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด ์ค€๋‹ค.

 

// useRef

import { useState, useMemo, useCallback, useRef } from "react";
const getAverage = (numbers) => {
  console.log("ํ‰๊ท ๊ฐ’ ๊ณ„์‚ฐ ์ค‘..");
  console.log(numbers);
  if (numbers.length === 0) return 0;
  const sum = numbers.reduce((a, b) => a + b);
  return sum / numbers.length;
};

const Average = () => {
  const [list, setList] = useState([]);
  const [number, setNumber] = useState("");
  const inputEl = useRef(null);

  const onChange = useCallback((e) => {
    setNumber(e.target.value);
  }, []); // ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ฒ˜์Œ ๋ Œ๋”๋ง๋  ๋•Œ๋งŒ ํ•จ์ˆ˜ ์ƒ์„ฑ

  const onInsert = useCallback(() => {
    const nextList = list.concat(parseInt(number));
    setList(nextList);
    setNumber("");
    inputEl.current.focus();
  }, [number, list]); // number ํ˜น์€ list ๊ฐ€ ๋ฐ”๋€Œ์—ˆ์„ ๋•Œ๋งŒ ํ•จ์ˆ˜ ์ƒ์„ฑ

  // ํŠน์ • ๊ฐ’์ด ๋ฐ”๋€Œ์—ˆ์„ ๋•Œ๋งŒ ์—ฐ์‚ฐ์„ ์‹คํ–‰ํ•˜๊ณ  ์›ํ•˜๋Š” ๊ฐ’์ด ๋ฐ”๋€Œ์ง€ ์•Š์•˜๋‹ค๋ฉด ์ด์ „์— ์—ฐ์‚ฐํ–ˆ๋˜ ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์‹œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹
  const avg = useMemo(() => getAverage(list), [list]);

  return (
    <div>
      <input value={number} onChange={onChange} ref={inputEl} />
      <button onClick={onInsert}>๋“ฑ๋ก</button>
      <ul>
        {list.map((value, index) => (
          <li key={index}>{value}</li>
        ))}
      </ul>
      {/* list ๋Š” value ๋งŒ ๋‹ด๊ธด ๋ฆฌ์ŠคํŠธ๋กœ ๋จ. */}
      <div>
        <b>ํ‰๊ท ๊ฐ’: </b> {avg}
      </div>
    </div>
  );
};

export default Average;

 

inputEl ์€ input ์š”์†Œ๋ฅผ ๋งํ•œ๋‹ค. inputEl.current ๊ฐ’์ด ์‹ค์ œ input ์š”์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค. ๋กœ์ปฌ ๋ณ€์ˆ˜๋Š” ๋ Œ๋”๋ง๊ณผ ์ƒ๊ด€์—†์ด ๋ฐ”๋€” ์ˆ˜ ์žˆ๋Š” ๊ฐ’์„ ์˜๋ฏธํ•œ๋‹ค.

 

 

 

 

 

 

 

๋„์„œ [๋ฆฌ์•กํŠธ๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ธฐ์ˆ ] ์„ ์ฐธ๊ณ ํ•˜์—ฌ ์ž‘์„ฑํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.