Jieunny์˜ ๋ธ”๋กœ๊ทธ

S4) Unit 4. [React] React Hooks ๋ณธ๋ฌธ

CodeStates/learning contents

S4) Unit 4. [React] React Hooks

Jieunny 2023. 3. 23. 12:57

๐Ÿ“ฃ  Hook ์ด๋ž€?

๐Ÿญ. Hook

โœ”๏ธ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ

โžฐ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ ์ด์ „์—๋Š” ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žˆ์—ˆ๋‹ค.

 

๐Ÿฎ. Class Component

class Counter extends Component {
    constructor(props) {
        super(props);
        this.state = {
            counter: 0
        }
        this.handleIncrease = this.handleIncrease.bind(this);
    }

    handleIncrease = () => {
        this.setState({
            counter: this.state.counter + 1
        })
    }

    render(){
       return (
            <div>
                <p>You clicked {this.state.counter} times</p>
                <button onClick={this.handleIncrease}>
                    Click me
                </button>
            </div>
       ) 
    }
}

โžฐ ๋‹จ์ˆœํžˆ ์นด์šดํŒ… ๊ธฐ๋Šฅ๋งŒ ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค๋”๋ผ๋„ ์œ„์ฒ˜๋Ÿผ ๋ณต์žกํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ–ˆ๋‹ค.

โžฐ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ต๊ณ , ์ปดํฌ๋„ŒํŠธ ์‚ฌ์ด์—์„œ ์ƒํƒœ ๋กœ์ง์„ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์–ด๋ ต๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.

โžฐ ๋˜ํ•œ this๋ฅผ ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๋ฉด ๋™์ž‘ ๋ฐฉ์‹ ์ž์ฒด๊ฐ€ ์–ด๋ ต๊ฒŒ ๋Š๊ปด์ง„๋‹ค.

 

๐Ÿฏ. Function Component

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

    const handleIncrease = () => {
        setCounter(counter + 1)
    }

    return (
        <div>
            <p>You clicked {counter} times</p>
            <button onClick={handleIncrease}>
                Click me
            </button>
        </div>
    )
}

โžฐ ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ์— ๋น„ํ•ด ํ›จ์”ฌ ๋” ์ง๊ด€์ ์ด๊ณ , ๋ณด๊ธฐ ์‰ฝ๋‹ค.

โžฐ ๋˜ํ•œ useState() ์ฒ˜๋Ÿผ Hook์„ ์‚ฌ์šฉํ•ด์„œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง ๋˜์–ด๋„ state๊ฐ€ ์œ ์ง€๋  ์ˆ˜ ์žˆ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๐Ÿฐ. Hook ์ด๋ž€?

โœ”๏ธ Hook์€ class๋ฅผ ์ž‘์„ฑํ•˜์ง€ ์•Š๊ณ ๋„ state์™€ ๋‹ค๋ฅธ React์˜ ๊ธฐ๋Šฅ๋“ค์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.

โžฐ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ ์ƒํƒœ ๊ฐ’ ๋ฐ ๋‹ค๋ฅธ ์—ฌ๋Ÿฌ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ธฐ ํŽธ๋ฆฌํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ๋ฉ”์†Œ๋“œ

โžฐ Hook์€ ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค => ์‚ฌ์šฉํ•˜๋ฉด ์—๋Ÿฌ ๋„์šด๋‹ค.

 

๐Ÿฑ. Hook ์‚ฌ์šฉ ๊ทœ์น™

1๏ธโƒฃ ๋ฆฌ์•กํŠธ ํ•จ์ˆ˜์˜ ์ตœ์ƒ์œ„์—์„œ๋งŒ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค.

โœ”๏ธ ๋ฐ˜๋ณต๋ฌธ, ์กฐ๊ฑด๋ฌธ, ์ค‘์ฒฉ๋œ ํ•จ์ˆ˜ ๋‚ด์—์„œ Hook์„ ์‹คํ–‰ํ•˜๋ฉด ์˜ˆ์ƒํ•œ ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค.

...
if(counter) {
    const [sample, setSample] = useState(0);
}
...

โžฐ useState๋ฅผ ์กฐ๊ฑด๋ฌธ ์•ˆ์—์„œ ํ˜ธ์ถœํ•˜๋ฉด ์•ˆ ๋œ๋‹ค๋Š” Error๋ฅผ ๋„์šด๋‹ค.

โžฐ React๋Š” ์ด Hook์„ ํ˜ธ์ถœ๋˜๋Š” ์ˆœ์„œ๋Œ€๋กœ ์ €์žฅ์„ ํ•ด๋†“๋Š”๋ฐ, ์กฐ๊ฑด๋ฌธ์ด๋‚˜ ๋ฐ˜๋ณต๋ฌธ์—์„œ ํ˜ธ์ถœํ•˜๊ฒŒ ๋˜๋ฉด ํ˜ธ์ถœ๋˜๋Š” ์ˆœ์„œ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์–ด๋ ค์›Œ์ง„๋‹ค.

 

2๏ธโƒฃ ์˜ค์ง ๋ฆฌ์•กํŠธ ํ•จ์ˆ˜ ๋‚ด์—์„œ๋งŒ ์‚ฌ์šฉ๋˜์–ด์•ผ ํ•œ๋‹ค.

โœ”๏ธ ๋ฆฌ์•กํŠธ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๋‚˜ ์ปค์Šคํ…€ Hook์ด ์•„๋‹Œ ๋‹ค๋ฅธ ์ผ๋ฐ˜ JavaScript ํ•จ์ˆ˜ ์•ˆ์—์„œ ํ˜ธ์ถœํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค.

...
window.onload = function () {
    useEffect(() => {
        // do something...
    }, [counter]);
}
...

โžฐ window.onload๋ผ๋Š” ํ•จ์ˆ˜์—์„œ useEffect๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์•ˆ ๋œ๋‹ค๋Š” Error๋ฅผ ๋„์šด๋‹ค.

โžฐ Hook์€ React์˜ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ์‚ฌ์šฉ๋˜๋„๋ก ๋งŒ๋“ค์–ด์ง„ ๋ฉ”์†Œ๋“œ์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ทผ๋ณธ์ ์œผ๋กœ ์ผ๋ฐ˜ JavaScript ํ•จ์ˆ˜ ๋‚ด์—์„œ๋Š” ์ •์ƒ์ ์œผ๋กœ ๋Œ์•„๊ฐ€์ง€ ์•Š๋Š”๋‹ค.


๐Ÿ“ฃ  useMemo๋ž€?

๐Ÿญ. useMemo

โœ”๏ธ ํŠน์ • ๊ฐ’(value)๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” Hook

import { useMemo } from "react";
function Calculator({value}){
    const result = useMemo(() => calculate(value), [value]);
    return <>
      <div>
        {result}
      </div>
    </>;
}
// props๋กœ ๋„˜์–ด์˜จ value ๊ฐ’์„ calculate ๋ผ๋Š” ํ•จ์ˆ˜์— ์ธ์ž๋กœ ๋„˜๊ฒจ์„œ 
// result ๊ฐ’์„ ๊ตฌํ•œ ํ›„, <div> ์—˜๋ฆฌ๋จผํŠธ๋กœ ์ถœ๋ ฅ

โžฐ ๋ Œ๋”๋ง์„ ํ•  ๋•Œ๋งˆ๋‹ค ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋˜๋ฉด, ๊ณ„์‚ฐ์— ๊ฑธ๋ฆฌ๋Š” ๋ช‡ ์ดˆ์˜ ์ง€์—ฐ์ด ๋ Œ๋”๋ง์—๋„ ์˜ํ–ฅ์„ ๋ฏธ์น  ๊ฒƒ์ด๋‹ค.

โžฐ useMemo๋ฅผ ์‚ฌ์šฉํ•ด์„œ value ๊ฐ’์„ ์–ด๋”˜๊ฐ€์— ์ €์žฅ์„ ํ•ด๋†จ๋‹ค๊ฐ€ ๋‹ค์‹œ ๊บผ๋‚ด์„œ ์“ธ ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ ๋‹ค.

(ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅํ•˜๋Š” ๊ฒŒ ์•„๋‹˜!)

โžฐ ์ด์ „์— ๊ตฌ์ถ•๋œ ๋ Œ๋”๋ง๊ณผ ์ƒˆ๋กœ์ด ๊ตฌ์ถ•๋˜๋Š” ๋ Œ๋”๋ง์„ ๋น„๊ตํ•ด์„œ value๊ฐ’์ด ๋™์ผํ•œ ๊ฒฝ์šฐ์—๋Š” ์ด์ „ ๋ Œ๋”๋ง์˜ value ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ์žฌํ™œ์šฉ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค => ๋ฉ”๋ชจ์ด์ œ์ด์…˜

 

๐Ÿฎ. Memoization

โœ”๏ธ ๊ธฐ์กด์— ์ˆ˜ํ–‰ํ•œ ์—ฐ์‚ฐ์˜ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅ์„ ํ•ด๋‘๊ณ , ๋™์ผํ•œ ์ž…๋ ฅ์ด ๋“ค์–ด์˜ค๋ฉด ์žฌํ™œ์šฉํ•˜๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ธฐ๋ฒ•

โžฐ ๊ตณ์ด ์ค‘๋ณต ์—ฐ์‚ฐ์„ ํ•  ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์•ฑ์˜ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค.


๐Ÿ“ฃ  useCallback ์ด๋ž€?

๐Ÿญ. useCallback

โœ”๏ธ ํ•จ์ˆ˜์˜ ์žฌ์‚ฌ์šฉ์„ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” Hook

/* useCallback๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์—๋Š” ๊ผญ importํ•ด์„œ ๋ถˆ๋Ÿฌ์™€์•ผ ํ•ฉ๋‹ˆ๋‹ค. */
import React, { useCallback } from "react";

function Calculator({x, y}){

	const add = useCallback(() => x + y, [x, y]);

	return <>
      <div>
					{add()}
      </div>
  </>;
}

โžฐ useCallback Hook์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ทธ ํ•จ์ˆ˜๊ฐ€ ์˜์กดํ•˜๋Š” ๊ฐ’๋“ค์ด ๋ฐ”๋€Œ์ง€ ์•Š๋Š” ํ•œ ๊ธฐ์กด ํ•จ์ˆ˜๋ฅผ ๊ณ„์†ํ•ด์„œ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

โžฐ ์ฆ‰, x์™€ y์˜ ๊ฐ’์ด ๋™์ผํ•˜๋‹ค๋ฉด ๋‹ค์Œ ๋ Œ๋”๋ง ๋•Œ ์ด ํ•จ์ˆ˜๋ฅผ ๋‹ค์‹œ ์‚ฌ์šฉํ•œ๋‹ค.

โžฐ useCallback์€ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ์„ ํ•˜์ง€ ์•Š๋Š” Hook์ด ์•„๋‹ˆ๋ผ, ๊ทธ์ € ๋ฉ”๋ชจ๋ฆฌ ์–ด๋”˜๊ฐ€์— ํ•จ์ˆ˜๋ฅผ ๊บผ๋‚ด์„œ ํ˜ธ์ถœํ•˜๋Š” Hook์ด๊ธฐ ๋•Œ๋ฌธ์— useMemo์— ๋น„ํ•ด์„œ ์ตœ์ ํ™”๋ฅผ ๋Š๋‚„ ์ˆ˜ ์—†๋‹ค.

โžฐ ๋‹จ์ˆœํžˆ ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜๋ณตํ•ด์„œ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ธฐ ์œ„ํ•ด์„œ useCallback์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ๋ณด๋‹ค๋Š” ์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ props๋กœ ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•ด์ค„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ์ข‹๋‹ค.

 

๐Ÿฎ. useCallback๊ณผ ์ฐธ์กฐ ๋™๋“ฑ์„ฑ

โžฐ React๋Š” ๋ฆฌ๋ Œ๋”๋ง ์‹œ ํ•จ์ˆ˜๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์„œ ํ˜ธ์ถœํ•˜๋ฉฐ, ์ด ํ•จ์ˆ˜๋Š” ๊ธฐ์กด์˜ ํ•จ์ˆ˜์™€ ๊ฐ™์€ ํ•จ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋‹ค.

(JS์—์„œ ํ•จ์ˆ˜๋Š” ๊ฐ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅํ•  ๋•Œ ๊ฐ’์„ ์ €์žฅํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ๊ฐ’์˜ ์ฃผ์†Œ๋ฅผ ์ €์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ)

โžฐ useCallback์„ ์ด์šฉํ•ด ํ•จ์ˆ˜ ์ž์ฒด๋ฅผ ์ €์žฅํ•ด์„œ ๋‹ค์‹œ ์‚ฌ์šฉํ•˜๋ฉด ํ•จ์ˆ˜์˜ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ ๊ฐ’์„ ์ €์žฅํ–ˆ๋‹ค๊ฐ€ ๋‹ค์‹œ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๊ฒƒ๊ณผ ๊ฐ™๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ React ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜ ๋‚ด์—์„œ ๋‹ค๋ฅธ ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ๋„˜๊ธฐ๊ฑฐ๋‚˜ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ prop์œผ๋กœ ๋„˜๊ธธ ๋•Œ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์„ฑ๋Šฅ ๋ฌธ์ œ๋ฅผ ๋ง‰์„ ์ˆ˜ ์žˆ๋‹ค.


๐Ÿ“ฃ  Custom Hooks ๋ž€?

๐Ÿญ. Custom Hooks

โœ”๏ธ ๊ฐœ๋ฐœ์ž๊ฐ€ ์Šค์Šค๋กœ ์ปค์Šคํ…€ํ•œ ํ›…

 

โœ”๏ธ Custom Hook์˜ ์žฅ์ 

โžฐ ๋ฐ˜๋ณต๋˜๋Š” ๋กœ์ง์„ ํ•จ์ˆ˜๋กœ ๋ฝ‘์•„๋‚ด์„œ ์žฌ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ๋‹ค.

โžฐ ์ƒํƒœ ๊ด€๋ฆฌ ๋กœ์ง์˜ ์žฌํ™œ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

โžฐ ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋ณด๋‹ค ์ ์€ ์–‘์˜ ์ฝ”๋“œ๋กœ ๋™์ผํ•œ ๋กœ์ง์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

โžฐ ํ•จ์ˆ˜ํ˜•์œผ๋กœ ์ž‘์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ณด๋‹ค ๋ช…๋ฃŒํ•˜๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.

 

โœ”๏ธ Custom Hook์„ ์ •์˜ํ•  ๋•Œ์˜ ๊ทœ์น™

โžฐ Custom Hook์„ ์ •์˜ํ•  ๋•Œ๋Š” ํ•จ์ˆ˜ ์ด๋ฆ„ ์•ž์— use๋ฅผ ๋ถ™์ด๋Š” ๊ฒƒ

โžฐ ๋Œ€๊ฐœ์˜ ๊ฒฝ์šฐ ํ”„๋กœ์ ํŠธ ๋‚ด์˜ hooks ๋””๋ ‰ํ† ๋ฆฌ์— Custom Hook์„ ์œ„์น˜ ์‹œํ‚จ๋‹ค.

โžฐ Custom Hook์œผ๋กœ ๋งŒ๋“ค ๋•Œ ํ•จ์ˆ˜๋Š” ์กฐ๊ฑด๋ถ€ ํ•จ์ˆ˜๊ฐ€ ์•„๋‹ˆ์–ด์•ผ ํ•œ๋‹ค. ์ฆ‰ return ํ•˜๋Š” ๊ฐ’์€ ์กฐ๊ฑด๋ถ€์—ฌ์„œ๋Š” ์•ˆ ๋œ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ž˜์˜ ์ด useFriendStatus Hook์€ ์˜จ๋ผ์ธ ์ƒํƒœ์˜ ์—ฌ๋ถ€๋ฅผ boolean ํƒ€์ž…์œผ๋กœ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์žˆ๋‹ค.

 

๐Ÿฎ. ์˜จ๋ผ์ธ์ธ์ง€ ์˜คํ”„๋ผ์ธ์ธ์ง€ ํ™•์ธํ•˜๋Š” ํ•จ์ˆ˜

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}

โžฐ ์ผ๋ฐ˜ ํ•จ์ˆ˜์—์„œ๋Š” ๋ถˆ๊ฐ€๋Šฅ ํ•˜์ง€๋งŒ, custom Hook์€ ๋‚ด๋ถ€์— React ๋‚ด์žฅ Hook์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

โžฐ ๊ฐ™์€ custom hook ์„ ์‚ฌ์šฉํ–ˆ๋‹ค๊ณ  ํ•ด์„œ ๋‘ ๊ฐœ์˜ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ฐ™์€ state๋ฅผ ๊ณต์œ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค.

โžฐ state๋Š” ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ๋…๋ฆฝ์ ์œผ๋กœ ์ •์˜๋˜์–ด ์žˆ๋‹ค.