GiantStepDEV
article thumbnail

Hook

  • ๋ฆฌ์•กํŠธ ๋ฒ„์ „ 16.8์— ์ƒˆ๋กœ ๋„์ž…๋œ ๊ธฐ๋Šฅ ์ž…๋‹ˆ๋‹ค.
  • ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ๋„ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋Š” useState, ๋ Œ๋”๋ง ์งํ›„ ์„ค์ •ํ•˜๋Š” useEffect ๋“ฑ์˜ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์—ฌ ๊ธฐ์กด์˜ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ ํ•  ์ˆ˜ ์—†์—ˆ๋˜ ๋‹ค์–‘ํ•œ ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  • Hook์€ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ React state์™€ ์ƒ๋ช…์ฃผ๊ธฐ ๊ธฐ๋Šฅ์„ ์—ฐ๋™ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ํ•จ์ˆ˜ ์ž…๋‹ˆ๋‹ค.

โญ๏ธ useState

  • useState()๋Š” ๋ฆฌ์•กํŠธ์—์„œ ์ƒํƒœ(state)๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์ œ๊ณต๋˜๋Š” hook ์ž…๋‹ˆ๋‹ค.
  • useState()๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ๋„ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ž๋™์œผ๋กœ ๋‹ค์‹œ ๋ Œ๋”๋ง ๋ฉ๋‹ˆ๋‹ค.
  • useState()๋Š” ๋ฐฐ์—ด ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜๋˜๋ฉฐ, ์ฒซ ๋ฒˆ์งธ ์š”์†Œ๋Š” 'ํ˜„์žฌ ์ƒํƒœ'์ด๊ณ , ๋‘ ๋ฒˆ์งธ ์š”์†Œ๋Š” '์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ํ•จ์ˆ˜' ์ž…๋‹ˆ๋‹ค. ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ํ•จ์ˆ˜๋Š” ์ž๋ฐ”์˜ Setterํ•จ์ˆ˜์™€ ๋น„์Šทํ•œ ์—ญํ• ์„ ํ•˜๋ฉฐ, ์ƒˆ๋กœ์šด ์ƒํƒœ๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋ง ํ•ฉ๋‹ˆ๋‹ค.

useState ๊ธฐ๋ณธ

const Usestate = () => {
  const [value, setValue] = useState(0); // ์ดˆ๊ธฐ๊ฐ’์„ 0์œผ๋กœ ์„ค์ •
  
  return (
    <>
      <p>ํ˜„์žฌ ์นด์šดํŠธ ๊ฐ’์€ <b>{value}</b></p>
      <button onClick={() => setValue(value + 1)}>์ฆ๊ฐ€</button>
      <button onClick={() => setValue(value - 1)}>๊ฐ์†Œ</button>
    </>
  );
}

export default Usestate;

๐Ÿข '์ฆ๊ฐ€' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•  ๋•Œ ๋งˆ๋‹ค(onClick()) value ๊ฐ’์„ 1 ์ฆ๊ฐ€ ์‹œํ‚จ ํ›„ ๋‹ค์‹œ ๋ Œ๋”๋ง ํ•ด๋ผ.(setValue(value + 1))

๐Ÿข '๊ฐ์†Œ' ๋ฒ„ํŠผ์„ ํด๋ฆญํ•  ๋•Œ ๋งˆ๋‹ค(onClick()) value ๊ฐ’์„ 1 ๊ฐ์†Œ ์‹œํ‚จ ํ›„ ๋‹ค์‹œ ๋ Œ๋”๋ง ํ•ด๋ผ.(setValue(value - 1))

์—ฐ์Šต๋ฌธ์ œ - ๋ช…ํ•จ ์ถœ๋ ฅํ•˜๊ธฐ

โœ๏ธ ์ด๋ฆ„, ์ง์ฑ…, ํšŒ์‚ฌ๋ช…, ํšŒ์‚ฌ์ฃผ์†Œ, ์ด๋ฉ”์ผ, ์ „ํ™”๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅ ๋ฐ›์•„ ๋ช…ํ•จ ํ˜•ํƒœ๋กœ ์ถœ๋ ฅํ•˜๊ธฐ

import React, { useState } from 'react';

// 7. ํ™”๋ฉด์— ์ถœ๋ ฅํ•  ๋ช…ํ•จ ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ
const NameCard = ({member}) => {

  return (
    <>
      <h3>๋ช…ํ•จ ์ •๋ณด ์ถœ๋ ฅ</h3>
      <p>์ด๋ฆ„ : {member.name}</p>
      <p>์ง์ฑ… : {member.position}</p>
      <p>ํšŒ์‚ฌ๋ช… : {member.company}</p>
      <p>์ฃผ์†Œ : {member.address}</p>
      <p>์ด๋ฉ”์ผ : {member.email}</p>
      <p>ํ•ธ๋“œํฐ : {member.phone}</p>
    </>
  );
}

const UserState = () => {
  const [member, setMember] = useState({ // 1. ๋ช…ํ•จ ์ •๋ณด ์ €์žฅ์„ ์œ„ํ•œ ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด ์ƒ์„ฑ
    name:"", 
    position:"", 
    company:"", 
    address:"", 
    email:"", 
    phone:""
  });
  
  const [submit, setSubmit] = useState(false);  // 2. ์ œ์ถœ์„ ๋ˆ„๋ฅด๊ธฐ ์ „๊นŒ์ง€๋Š” ์•ˆ๋‚˜์˜ค๊ฒŒ ํ•˜๋ ค๊ณ  boolean ํƒ€์ž…์œผ๋กœ ์„ค์ •
  
  // 3. member ๊ฐ์ฒด(์œ„์— ๋นˆ ๊ณต๊ฐ„์˜ ๊ฐ์ฒด)๋ฅผ ํŽผ์น˜๊ณ , name์— ์ด๋ฒคํŠธ๊ฐ€ ์ผ์–ด๋‚œ ๊ฐ’์„ ๋„ฃ๋Š” ๊ฒƒ - ๋‹ค๋ฅธ ํ•ญ๋ชฉ ์ดํ•˜ ๋™์ผ
    // ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ: onChange, onClick ...๋ฅผ ์ด์šฉํ•ด์„œ ๊ฐ’์„ ๋ฐ›์•„์˜ค๊ธฐ
  const onChangeName = (e) => setMember({...member, name: e.target.value});
  const onChangePosition = (e) => setMember({...member, position: e.target.value});
  const onChangeCompany = (e) => setMember({...member, company: e.target.value});
  const onChanageAddress = (e) => setMember({...member, address: e.target.value});
  const onChangeEmail = (e) => setMember({...member, email: e.target.value});
  const onChangePhone = (e) => setMember({...member, phone: e.target.value});

  // 4. ๊ฐ’์„ ์ž…๋ ฅํ•˜๊ณ  ์ œ์ถœ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ submit ์ƒํƒœ๋ฅผ true๋กœ ๋ณ€๊ฒฝ
  const onSubmit = () => {
    setSubmit(true);
  }

  // 5. ์œ„์— ๋งŒ๋“  ๊ฒƒ๋“ค์„ ์ ์ ˆํ•œ ์œ„์น˜์— ๋„ฃ๊ธฐ
  return (
    <>
      <h1>ํšŒ์› ์ •๋ณด</h1>
      <input type="text" placeholder='์ด๋ฆ„' value={member.name} onChange={onChangeName}/><br />
      <input type="text" placeholder='์ง์ฑ…' value={member.position} onChange={onChangePosition}/><br />
      <input type="text" placeholder='ํšŒ์‚ฌ๋ช…' value={member.company} onChange={onChangeCompany}/><br />
      <input type="text" placeholder='์ฃผ์†Œ' value={member.address} onChange={onChanageAddress}/><br />
      <input type="text" placeholder='๋ฉ”์ผ' value={member.email} onChange={onChangeEmail}/><br />
      <input type="text" placeholder='ํ•ธ๋“œํฐ' value={member.phone} onChange={onChangePhone}/>
      <button onClick={onSubmit}>์ œ์ถœ</button>
      
      {/* 6. ์ปดํฌ๋„ŒํŠธ ๋„ฃ์–ด์„œ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง */}
      {/* member={member} <= member๋Š” props ์ด๋ฆ„์ด๋ผ ์ž„์˜๋กœ ์„ค์ • ๊ฐ€๋Šฅ, {member}๋Š” ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด ์ด๋ฆ„ */}
      {submit && <NameCard member={member}/>}
    </>
  );
}

export default UserState;

โญ๏ธ useEffect

  • React ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ '์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์†Œ๋“œ๋ฅผ ๋Œ€์ฒด'ํ•˜๋Š” React hook ์ž…๋‹ˆ๋‹ค. (ํ•„์ˆ˜ ์‚ฌ์šฉ)
    ๐Ÿข ์ƒ๋ช…์ฃผ๊ธฐ? : ํ™”๋ฉด์— ๋‚˜ํƒ€๋‚ฌ๋‹ค๊ฐ€ ์‚ฌ๋ผ์งˆ ๋•Œ๊นŒ์ง€ ์ผ๋ จ์˜ ๊ณผ์ •
  • useEffect๋Š” 1) ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง ๋  ๋•Œ๋งˆ๋‹ค ํŠน์ • ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๊ฑฐ๋‚˜, 2) ํŠน์ • ์ƒํƒœ๊ฐ€ ์—…๋ฐ์ดํŠธ ๋  ๋•Œ๋งˆ๋‹ค ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋กœ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ๋ฐ›๊ณ , ์ด ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ(ํ™”๋ฉด์— ๊ทธ๋ ค์งˆ ๋•Œ) ๋˜๊ฑฐ๋‚˜ ์–ธ๋งˆ์šดํŠธ(ํ™”๋ฉด์—์„œ ์‚ฌ๋ผ์ง€๋Š”) ๋  ๋•Œ, ๊ทธ๋ฆฌ๊ณ  ์˜์กด์„ฑ ๋ฐฐ์—ด์— ์ „๋‹ฌ๋œ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ ๋  ๋•Œ๋งˆ๋‹ค ์‹คํ–‰ ๋ฉ๋‹ˆ๋‹ค.
  • ๋‘ ๋ฒˆ์งธ ์ธ์ž๋กœ ์˜์กด์„ฑ ๋ฐฐ์—ด์ด ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค. ์˜์กด์„ฑ ๋ฐฐ์—ด์ด ๋นˆ ๋ฐฐ์—ด์ด๋ฉด useEffect๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ ๋  ๋•Œ ํ•œ๋ฒˆ๋งŒ ์‹คํ–‰ ๋ฉ๋‹ˆ๋‹ค.
useEffect ์•ˆ์—๋Š” ์„œ๋ฒ„์— ๋ณด๋‚ผ ๋ช…๋ น์„ ์ž‘์„ฑํ•จ. (axios)
์˜์กด์„ฑ ๋ฐฐ์—ด : ๋น„๊ต๋Š” ๋น ๋ฅธ ์†๋„๋ฅผ ์œ„ํ•ด '์ฃผ์†Œ'๋งŒ ๋น„๊ตํ•˜์—ฌ ๋‹ฌ๋ผ์กŒ์œผ๋ฉด ๋ Œ๋”๋ง ํ•œ๋‹ค. (๋ถˆ๋ณ€์„ฑ์˜ ๋ฒ•์น™)

โญ๏ธ useState๋ž‘ useEffect๋ฅผ ๊ฐ™์ด ๋„ฃ์œผ๋ฉด ๋ฌดํ•œ๋ฃจํ”„์— ๋น ์งˆ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์กฐ์‹ฌ.

import React, { useState, useEffect } from "react";

const UseEffectInfo = () => {
  const [name, setName] = useState(""); // ์ด๋ฆ„์ด ๋ฐ”๋€” ๋•Œ๋งˆ๋‹ค ํ™”๋ฉด์„ ๋ Œ๋”๋ง ํ•˜๊ธฐ ์œ„ํ•œ
  const [nickname, setNickname] = useState("");

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

  const onChangeName = e => setName(e.target.value);
  const onChangeNickname = e => setNickname(e.target.value);

  return (
    <>
      <div>
        <input type="text" value={name} onChange={onChangeName} />
        <input type="text" value={nickname} onChange={onChangeNickname} />
      </div>
      <div>
        <p>์ด๋ฆ„์€ <b>{name}</b></p>
        <p>๋‹‰๋„ค์ž„์€ <b>{nickname}</b></p>
      </div>
    </>
  );
}

export default UseEffectInfo;

ํŠน์ • ๊ฐ’์ด ์—…๋ฐ์ดํŠธ ๋  ๋•Œ๋งŒ ์‹คํ–‰ํ•˜๊ณ  ์‹ถ์„ ๋•Œ

  • useEffect() ์˜ ๋‘๋ฒˆ์งธ ์ธ์ž๋กœ ์ „๋‹ฌ๋˜๋Š” ๋ฐฐ์—ด ์•ˆ์— ๊ฒ€์‚ฌํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฐ’์„ ๋„ฃ์œผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
  • ๋ฐฐ์—ด ์•ˆ์—๋Š” useState๋ฅผ ํ†ตํ•ด ๊ด€๋ฆฌํ•˜๊ณ  ์žˆ๋Š” ์ƒํƒœ ๊ฐ’์„ ๋„ฃ์–ด๋„ ๋˜๊ณ , props๋กœ ์ „๋‹ฌ๋ฐ›์€ ๊ฐ’์„ ๋„ฃ์–ด๋„ ๋ฉ๋‹ˆ๋‹ค.
import React, { useState, useEffect } from "react";

const UseEffectCnt = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log(`You clicked ${count} times`);
  }, [count]); // count ๊ฐ’์ด ๋ฐ”๋€” ๋•Œ๋งˆ๋‹ค ์ฝœ๋ฐฑํ•จ์ˆ˜ ์‹คํ–‰
  // useEffect๋Š” useState์™€ ๋ณ„๊ฐœ๋กœ ์‹คํ–‰๋จ. ํ™”๋ฉด์ด ๊ทธ๋ ค์ง„ ํ›„ ์˜์กด์„ฑ ๋ฐฐ์—ด์˜ ๊ฐ’์ด ๋ฐ”๋€” ๋•Œ ์‹คํ–‰.

  return (
    <>
      <p>You Clicked {count} times.</p>
      <button onClick={() => setCount(count + 1)}>Click me!</button>
    </>
  );
}

export default UseEffectCnt;

์‹œ๊ฐ„ ์—…๋ฐ์ดํŠธ ํ•˜๊ธฐ

  • clearInterval() ํ•จ์ˆ˜๋Š” JavaScript์—์„œ ์ œ๊ณตํ•˜๋Š” ํ•จ์ˆ˜๋กœ, setInterval() ํ•จ์ˆ˜๋กœ ์ƒ์„ฑํ•œ ์ธํ„ฐ๋ฒŒ์„ ๋ฉˆ์ถ”๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
import React, { useState, useEffect } from "react";

const UseEffectClock = () => {
  const [time, setTime] = useState(new Date());

  useEffect(() => {
    const interval = setInterval(() => {
      setTime(new Date());
    }, 1000);

    // ์–ธ๋งˆ์šดํŠธ ๋˜๋ฉด interval์„ ํ•ด์ œ
    return() => clearInterval(interval);
  }, []);

  return (
    <>
      <h1>ํ˜„์žฌ ์‹œ๊ฐ„์€ {time.toLocaleTimeString()}</h1>
    </>
  );
}

export default UseEffectClock;

useReducer

  • useReducer๋Š” ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
    useState์™€ ๋‹ฌ๋ฆฌ, useReducer๋Š” ๋ณต์žกํ•œ ๋กœ์ง์„ ๊ฐ€์ง„ ์ƒํƒœ๋“ค์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐ์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋Š” '์ƒํƒœ ์—…๋ฐ์ดํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•จ์ˆ˜'๋กœ์„œ "reducer"๋ผ๊ณ  ๋ถˆ๋ฆฝ๋‹ˆ๋‹ค.
    ๋‘ ๋ฒˆ์งธ ์ธ์ž๋Š” '์ดˆ๊ธฐ ์ƒํƒœ' ์ž…๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ํ˜„์žฌ ์ƒํƒœ์™€ ์•ก์…˜(action) ๊ฐ์ฒด๋ฅผ ๋ฐ›์•„์„œ ์ƒˆ๋กœ์šด ์ƒํƒœ๋ฅผ ๋ฐ˜ํ™˜ ํ•ฉ๋‹ˆ๋‹ค.
  • useReducer๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด dispatch๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • dispatch ํ•จ์ˆ˜๋Š” ์•ก์…˜ ๊ฐ์ฒด๋ฅผ ๋ฐ›๊ณ , ์ด ์•ก์…˜ ๊ฐ์ฒด๋Š” ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•  ๋•Œ ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
import React, { useReducer } from "react";
  // state : ํ˜„์žฌ ์ƒํƒœ
  // dispatch : ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ํ•จ์ˆ˜
  // reducer : ๊ฐœ๋ฐœ์ž๊ฐ€ ์™ธ๋ถ€์— ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š” ํ•จ์ˆ˜
const reducer = (state, action) => {
  // ์•ก์…˜์˜ ํƒ€์ž…์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์ž‘์—… ์ˆ˜ํ–‰
  switch(action.type) {
    case "INCREMENT" :
      return {value: state.value + 1};
    case "DECREMENT" :
      return {value: state.value -1};
    default :
      return state;
  }
}
const UseReducerCnt = () => {
  const [state, dispatch] = useReducer(reducer, {value:0});

  return (
    <>
      <p>ํ˜„์žฌ ์นด์šดํŠธ ๊ฐ’์€ <b>{state.value}</b></p>
      <button onClick={() => dispatch({type: "INCREMENT"})}>+1</button>
      <button onClick={() => dispatch({type: "DECREMENT"})}>-1</button>
    </>
  );
}

export default UseReducerCnt;

์œ„ ์ฝ”๋“œ๋Š” useState๋กœ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ, ๋ณต์žกํ•˜์ง€ ์•Š์œผ๋ฉด useState์— ๋น„ํ•ด ํฐ ์ด์ ์€ ์—†์Œ.
Redux์™€ ๊ฒฐํ•ฉํ•ด์•ผ ์ด์ ์ด ์žˆ๋Š”๋ฐ ๊ทธ๋งˆ์ €๋„ Context API๋กœ ๋Œ€์ฒดํ•ด๋„ ๋จ

โญ๏ธ useMemo

  • ์ปดํฌ๋„ŒํŠธ์˜ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • Memo๋Š” "memorized"๋ฅผ ์˜๋ฏธํ•˜๋ฉฐ, ์ด์ „์— ๊ณ„์‚ฐํ•œ ๊ฐ’์„ ์žฌ์‚ฌ์šฉํ•œ๋‹ค๋Š” ์˜๋ฏธ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ Œ๋”๋งํ•˜๋Š” ๋™์•ˆ, ์ปดํฌ๋„ŒํŠธ์˜ ์ƒํƒœ๋‚˜ props๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์™€ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๋“ค์ด ๋‹ค์‹œ ๋ Œ๋”๋ง ๋ฉ๋‹ˆ๋‹ค.
    ์ด๋Ÿฌํ•œ ๋ถˆํ•„์š”ํ•œ ๋ Œ๋”๋ง์€ ์„ฑ๋Šฅ ๋ฌธ์ œ๋ฅผ ์•ผ๊ธฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ด์œ ๋กœ useMemo๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ตœ์ ํ™” ํ•ฉ๋‹ˆ๋‹ค.
  • useMemo(๊ณ„์‚ฐํ•˜๋Š” ํ•จ์ˆ˜, ์˜์กด์„ฑ ๋ฐฐ์—ด)

์ผ๋ฐ˜์ ์ธ ๊ตฌํ˜„ ๋ฐฉ์‹

  • ์ผ๋ฐ˜์ ์ธ ๊ตฌํ˜„ ๋ฐฉ์‹์œผ๋กœ ์ž‘์„ฑํ•  ๊ฒฝ์šฐ, Input ๋‚ด์šฉ์ด ์ˆ˜์ • ๋  ๋•Œ๋งˆ๋‹ค getAverage ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
  • input ๋‚ด์šฉ์ด ๋ฐ”๋€” ๋•Œ๋งˆ๋‹ค ...์ฆ‰ ๋ฆฌ๋ Œ๋”๋ง ํ•  ๋•Œ๋งˆ๋‹ค ํ‰๊ท ๊ฐ’์„ ๊ณ„์‚ฐํ•˜๋Š” ๊ฒƒ์€ ๋ถˆํ•„์š”ํ•œ ์ผ ์ž…๋‹ˆ๋‹ค.
import { useState } from "react";

const getAverage = numbers => {
    console.log("ํ‰๊ท ๊ฐ’ ๊ณ„์‚ฐ ์ค‘");
    if(numbers.length === 0) return 0;
    // ๋ฐฐ์—ด์˜ ๊ฐ ์š”์†Œ๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ callback ํ•จ์ˆ˜์˜ ์‹คํ–‰ ๊ฐ’์„ ๋ˆ„์ ํ•˜์—ฌ ํ•˜๋‚˜์˜ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฐ˜ํ™˜ ํ•ฉ๋‹ˆ๋‹ค.
    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 = e => {
        const nextList = list.concat(parseInt(number));
        setList(nextList);
        setNumber('');
    };
    return (
        <div>
            <input value={number} onChange={onChange} />
            <button onClick={onInsert}>๋“ฑ๋ก</button>
            <ul>
                {list.map((value, index) => <li key={index}>{value}</li>)}
            </ul>
            <div>
                <b>ํ‰๊ท ๊ฐ’ : </b> {getAverage(list)}
            </div>
        </div>
    );
};
export default Average;

useMemo๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹

  • useMemo๋Š” ๋‘ ๊ฐœ์˜ ์ธ์ž๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค.
    ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋Š” ์บ์‹œํ•  ๊ฐ’์„ ๊ณ„์‚ฐํ•˜๋Š” ํ•จ์ˆ˜์ด๊ณ , ๋‘ ๋ฒˆ์งธ ์ธ์ž๋Š” ์˜์กด์„ฑ ๋ฐฐ์—ด ์ž…๋‹ˆ๋‹ค.
  • ์˜์กด์„ฑ ๋ฐฐ์—ด์€ useMemo๊ฐ€ ์–ธ์ œ ์บ์‹œ๋œ ๊ฐ’์„ ๋‹ค์‹œ ๊ณ„์‚ฐํ•ด์•ผ ํ•˜๋Š”์ง€ ๊ฒฐ์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • ์˜์กด์„ฑ ๋ฐฐ์—ด์— ์žˆ๋Š” ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์œผ๋ฉด useMemo๋Š” ์ด์ „์— ์บ์‹œ๋œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ณ , ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋ฉด ์ƒˆ๋กœ์šด ๊ฐ’์„ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.
    (์ฆ‰, ์•„๋ž˜ ์˜ˆ์ œ ์ฝ”๋“œ์—์„œ list ๋ฐฐ์—ด์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค getAverage ํ•จ์ˆ˜๊ฐ€ ๋‹ค์‹œ ์‹คํ–‰ ๋ฉ๋‹ˆ๋‹ค.
    list ๋ฐฐ์—ด์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ์—๋Š” ์ด์ „์— ๊ณ„์‚ฐ๋œ ๊ฐ’์„ ์žฌ์‚ฌ์šฉ ํ•ฉ๋‹ˆ๋‹ค.)
import React, { useMemo, useState } from "react";

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

  const onChange = e => setNumber(e.target.value);
  const onInsert = () => {
    // ํ˜„์žฌ ์ž…๋ ฅ ๋ฐ›์€ ์ˆซ์ž๋ฅผ ๊ธฐ์กด์˜ ๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€(concat์œผ๋กœ ์ถ”๊ฐ€ ํ–ˆ์œผ๋ฏ€๋กœ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์ด ์ƒ์„ฑ๋จ. 
    // ๐Ÿ‘‰ ๋ถˆ๋ณ€์„ฑ์˜ ์›์น™
    const nextList = list.concat(parseInt(number));
    setList(nextList);
    setNumber("");
  }

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

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

  return (
    <>
      <input type="text" value={number} onChange={onChange} />
      <button onClick={onInsert}>๋“ฑ๋ก</button>
      <ul>
        {list.map((value, index) => <li key={index}>{value}</li>)}
      </ul>
      <div>
        <b>ํ‰๊ท ๊ฐ’ : </b> {avg}
      </div>
    </>
  );
}

export default Average;

useCallback

  • useCallback์€ useMemo์™€ ์ƒ๋‹นํžˆ ๋น„์Šทํ•œ ํ•จ์ˆ˜ ์ž…๋‹ˆ๋‹ค.
  • ์ฃผ๋กœ ๋ Œ๋”๋ง ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์—์„œ ์‚ฌ์šฉํ•˜๋ฉฐ, useCallback์„ ์‚ฌ์šฉํ•˜๋ฉด ๋งŒ๋“ค์–ด๋†จ๋˜ ํ•จ์ˆ˜๋ฅผ ์žฌ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
import { useState, useMemo, useCallback } from "react";

const getAverage = numbers => {
    console.log("ํ‰๊ท ๊ฐ’ ๊ณ„์‚ฐ ์ค‘");
    if(numbers.length === 0) return 0;
    // ๋ฐฐ์—ด์˜ ๊ฐ ์š”์†Œ๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ callback ํ•จ์ˆ˜์˜ ์‹คํ–‰ ๊ฐ’์„ ๋ˆ„์ ํ•˜์—ฌ ํ•˜๋‚˜์˜ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฐ˜ํ™˜ ํ•ฉ๋‹ˆ๋‹ค.
    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]);

    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>
            <div>
                <b>ํ‰๊ท ๊ฐ’ : </b> {avg}
            </div>
        </div>
    );
};
export default Average;

useRef

  • ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ ref๋ฅผ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค๋‹ˆ๋‹ค.
  • useRef๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ref๋ฅผ ์„ค์ •ํ•˜๋ฉด useRef๋ฅผ ํ†ตํ•ด ๋งŒ๋“  ๊ฐ์ฒด ์•ˆ์˜ current๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค.
import { useState, useMemo, useCallback, useRef } from "react";

const getAverage = numbers => {
    console.log("ํ‰๊ท ๊ฐ’ ๊ณ„์‚ฐ ์ค‘" + numbers);
    if(numbers.length === 0) return 0;
    // ๋ฐฐ์—ด์˜ ๊ฐ ์š”์†Œ๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ callback ํ•จ์ˆ˜์˜ ์‹คํ–‰ ๊ฐ’์„ ๋ˆ„์ ํ•˜์—ฌ ํ•˜๋‚˜์˜ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฐ˜ํ™˜ ํ•ฉ๋‹ˆ๋‹ค.
    const sum = numbers.reduce((a, b) => a + b);
    return sum / numbers.length;
};

const Average = () => {  // ์ปดํฌ๋„ŒํŠธ ์ด๋ฆ„์€ ๋Œ€๋ฌธ์ž
    const [list, setList] = useState([]);
    const [number, setNumber] = useState(0);
    const inputEl = useRef(null);

    const onChange = useCallback(e => {
        setNumber(e.target.value);
    }, []); // ๋นˆ ๋ฐฐ์—ด์„ ๋„ฃ์œผ๋ฉด ์ฒ˜์Œ ๋ Œ๋”๋ง๋  ๋•Œ๋งŒ ํ•จ์ˆ˜ ํ˜ธ์ถœ

    const onInsert = useCallback(() => {
        const nextList = list.concat(parseInt(number));
        setList(nextList);
        setNumber(0);
        inputEl.current.focus();
    }, [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>
            <div>
                <b>ํ‰๊ท ๊ฐ’ : </b> {avg}
            </div>
        </div>
    );
};
export default Average;
profile

GiantStepDEV

@kongmi

ํฌ์ŠคํŒ…์ด ์ข‹์•˜๋‹ค๋ฉด "์ข‹์•„์š”โค๏ธ" ๋˜๋Š” "๊ตฌ๋…๐Ÿ‘๐Ÿป" ํ•ด์ฃผ์„ธ์š”!