Skip to content

Latest commit

ย 

History

History
453 lines (308 loc) ยท 12.8 KB

hooks.md

File metadata and controls

453 lines (308 loc) ยท 12.8 KB

Hooks

Hook์€ React 16.8 ๋ฒ„์ „๋ถ€ํ„ฐ ์ƒˆ๋กญ๊ฒŒ ์ถ”๊ฐ€๋œ ์ƒํƒœ ๋ฐ ์ƒ๋ช…์ฃผ๊ธฐ ๊ด€๋ฆฌ API์ด๋‹ค. Hook์„ ์‚ฌ์šฉํ•˜๋ฉด ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์˜ ์‚ฌ์šฉ ์—†์ด ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ์ƒํƒœ ์ €์žฅ์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ ์ƒ๋ช…์ฃผ๊ธฐ ๊ด€๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค.


useState

useState๋Š” ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ hook์ด๋‹ค.

Create initial state

const [<์ƒํƒœ ์ €์žฅ ๋ณ€์ˆ˜>, <์ƒํƒœ ๊ฐฑ์‹  ํ•จ์ˆ˜>] = useState(<์ƒํƒœ ์ดˆ๊ธฐ ๊ฐ’>);

์ดˆ๊ธฐ state ์ƒ์„ฑ์‹œ ์ƒํƒœ ์ €์žฅ ๋ณ€์ˆ˜์˜ ์ดˆ๊ธฐ ๊ฐ’์„ array, number, boolean ๋“ฑ ๋‹ค์–‘ํ•œ ํƒ€์ž… ๋ฐ ๊ฐ’์œผ๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ useState๋Š” ๊ฐ’์ด ์•„๋‹Œ ํ•จ์ˆ˜๋ฅผ ์ธ์ž๋กœ ๊ฐ€์งˆ์ˆ˜ ์žˆ๋Š”๋ฐ ์ด ๊ฒฝ์šฐ, ์ฒซ ๋ Œ๋”๋ง๋ ๋•Œ๋งŒ ์‹คํ–‰๋œ๋‹ค.


Update State

const [count, setCount] = useState(0)

setCount(prevCount => prevCount + 1)

์ดˆ๊ธฐ state ์ƒ์„ฑ์‹œ ์„ ์–ธํ•œ ์ƒํƒœ ๊ฐฑ์‹  ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ƒํƒœ ์ €์žฅ ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ๊ฐฑ์‹ ํ•  ์ˆ˜ ์žˆ๋‹ค.


Example

useState hook๊ณผ ์ƒํƒœ ์ €์žฅ ๋ณ€์ˆ˜ count๋ฅผ ์‚ฌ์šฉํ•œ ์นด์šดํ„ฐ ์˜ˆ์ œ

function Counter() {
  const [count, setCount] = useState(0) // creating initial state

  function changeCount(amount) {
    setCount(prevCount => prevCount + amount)
  }

  function resetCount() {
    setCount(0)
  }

  return (
    <>
      <span>{count}</span>
      <button onClick={() => changeCount(1)}>+</button>
      <button onClick={() => changeCount(-1)}>-</button>
      <button onClick={() => resetCount()}>Reset</button>
    </>
  )
}


useEffect

i

useEffect(function, deps)

useEffect๋Š” ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์˜ ๋ผ์ดํ”„์‚ฌ์ดํด ๋ฉ”์†Œ๋“œ๋ฅผ ๋Œ€์ฒดํ•˜๋ฉฐ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง์‹œ ํ˜น์€ ๋ Œ๋”๋ง ์ดํ›„ ํŠน์ • ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋„๋กํ•˜๋Š” hook์ด๋‹ค.


Creating Your First Side Effect

๋„คํŠธ์›Œํฌ ์š”์ฒญ, ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ, ๊ตฌ๋… ์„ค์ •, ์ˆ˜๋™์œผ๋กœ ์ปดํฌ๋„ŒํŠธ์˜ DOM์„ ์ˆ˜์ •ํ•˜๋Š” ๋“ฑ ํ˜„์žฌ ํ•จ์ˆ˜์˜ ๋ฒ”์œ„์— ๋ฒ—์–ด๋‚œ ๊ฒƒ์— ์˜ํ–ฅ์„ ๋ผ์น˜๋Š” ๊ฒƒ์„ side effect๋ผ๊ณ  ํ•œ๋‹ค. useEffect๋Š” ์ด๋Ÿฌํ•œ side effect ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค.

useEffect๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ•์€ ๋‹จ์ผ ํ•จ์ˆ˜(single function)๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

useEffect(() => {
  console.log('This is a side effect')
})

์ด ๊ฒฝ์šฐ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ฒ˜์Œ ๋งˆ์šดํŠธ๋  ๋•Œ, props๊ฐ€ ๋ณ€๊ฒฝ ๋  ๋•Œ, ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ ๋  ๋•Œ ๋“ฑ ๋ Œ๋”๋ง ๋  ๋•Œ๋งˆ๋‹ค ์‹คํ–‰๋œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋งˆ์šดํŠธ ๋‹จ๊ณ„์—์„œ๋งŒ side effect๊ฐ€ ํ•„์š”ํ•˜๊ฑฐ๋‚˜ ํŠน์ • props๋‚˜ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์ด์ƒ์ ์ด์ง€ ์•Š๋‹ค.

๋‘๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜์ธ ์˜์กด์„ฑ ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜๋ฉด ์ด์ „ ๋ Œ๋”๋ง์˜ ์˜์กด์„ฑ๊ณผ ๋น„๊ตํ•ด ๋งˆ์ง€๋ง‰ ๋ Œ๋”๋ง ์ดํ›„ ์˜์กด์„ฑ์ด ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ side effect๊ฐ€ ์‹คํ–‰๋œ๋‹ค. ๋งˆ์šดํŠธ ๋‹จ๊ณ„์—์„œ๋งŒ ์‹คํ–‰ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๋นˆ ๋ฐฐ์—ด์„ ๋‘๋ฒˆ์งธ ๋งค๊ฐœ ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌํ•˜๋ฉด ๋œ๋‹ค.

useEffect(() => {
  console.log('Only run on mount')
}, [])


useEffect(() => {
  console.log('Only run on url change')
}, [url])

Cleaning Up Side Effects

์–ธ๋งˆ์šดํŠธ ์ด์ „, ์—…๋ฐ์ดํŠธ ์ง์ „์— side effect๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด clean up ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผํ•œ๋‹ค.

useEffect(() => {
  console.log('This is my side effect')

  return () => {
    console.log('This is my clean up')
  }
})

์œ„์™€ ๊ฐ™์€ useEffect๋ฅผ ํฌํ•จํ•œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ ํ›„ ๋ฆฌ๋ Œ๋”๋ง 2ํšŒ ๊ทธ๋ฆฌ๊ณ  ์–ธ๋งˆ์šดํŠธ ๋  ๊ฒฝ์šฐ ์•„๋ž˜์™€ ๊ฐ™์ด ์ฝ˜์†” ์ถœ๋ ฅํ•˜๊ฒŒ ๋œ๋‹ค.

// MOUNTED
// This is my side effect

// RE-RENDER 1:
// This is my clean up
// This is my side effect

// RE-RENDER 2:
// This is my clean up
// This is my side effect

// UN-MOUNT:
// This is my clean up


useMemo & useCallback

useMemo์™€ useCallback hook์„ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” memoization์— ๋Œ€ํ•ด ์•Œ์•„์•ผํ•œ๋‹ค.


What is Memoization?

Memoization์€ ๋ณธ์งˆ์ ์œผ๋กœ ์บ์‹ฑ๊ณผ ๊ฐ™์€ ์˜๋ฏธ์ด๋‹ค. ๋™์ผํ•œ ๊ณ„์‚ฐ์„ ๋ฐ˜๋ณตํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ• ๋•Œ ๊ฐ’์„ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜๋Š” ๋Œ€์‹  ์บ์‹œ๋œ ๊ฐ’์„ ์‚ฌ์šฉํ•ด ์ฒ˜๋ฆฌ ์†๋„๋ฅผ ๋น ๋ฅด๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ค๋Š” ๊ฒƒ์ด memoization์ด๋‹ค.

const cache = {}

function slow(a) {
  if (cache[a]) return cache[a]
  
  const result = /* Complex logic */
  cache[a] = result
  return result
}

๋ Œ๋”๋ง ๋  ๋•Œ๋งˆ๋‹ค ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ ๋กœ์ง์ด ์žฌ๊ณ„์‚ฐ๋˜๊ณ  ๋กœ์ง์˜ ๊ณ„์‚ฐ์†๋„๊ฐ€ ๋Š๋ฆฐ ๊ฒฝ์šฐ ๊ธ‰๊ฒฉํ•œ ์†๋„์ €ํ•˜๊ฐ€ ์ผ์–ด๋‚˜๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ hook์ด ๋ฐ”๋กœ useMemo์™€ useCallback์ด๋‹ค.


useMemo

useMemo๋Š” useEffect์™€ ๋น„์Šทํ•œ ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•˜๋ฉฐ ๋‘๋ฒˆ์งธ ์ธ์ž์ธ ์˜์กด์„ฑ์ด ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ๋งŒ memoization๋œ ๊ฐ’๋งŒ ๋‹ค์‹œ ๊ณ„์‚ฐํ•œ๋‹ค. ์ฆ‰, useMemo๋Š” memoization๋œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

const result = useMemo(() => {
  return slowFunction(a)
}, [a])

useMemo๋กœ ์ „๋‹ฌ๋œ ํ•จ์ˆ˜๋Š” ๋ Œ๋”๋ง ์ค‘์— ์‹คํ–‰๋œ๋‹ค. ๋‘๋ฒˆ์งธ ์ธ์ž๊ฐ€ ์—†์„ ๊ฒฝ์šฐ ๋ Œ๋”๋ง ๋  ๋•Œ๋งˆ๋‹ค ์ƒˆ ๊ฐ’์„ ๊ณ„์‚ฐํ•œ๋‹ค.


useCallback

useCallback์€ ์˜์กด์„ฑ ๋ฐฐ์—ด์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œํ•˜๊ธฐ ๋•Œ๋ฌธ์— useMemo์™€ ๋™์ผํ•˜๊ฒŒ ์ž‘๋™ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ useCallback์€ ์บ์‹ฑ๋œ ๊ฐ’์ด ์•„๋‹Œ ์บ์‹ฑ๋œ ํ•จ์ˆ˜๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค. ์ฆ‰, useCallback์€ memoization๋œ ์ฝœ๋ฐฑ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

const handleReset = useCallback(() => {
  return doSomething(a, b)
}, [a, b])

๊ตฌ๋ฌธ์ƒ์€ useMemo์™€ ๋™์ผํ•˜์ง€๋งŒ useMemo๋Š” ์˜์กด์„ฑ์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์ „๋‹ฌ๋œ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ ํ›„ ํ˜ธ์ถœ์— ๋Œ€ํ•œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋ฐ˜๋ฉด์— useCallback์€ ์˜์กด์„ฑ์ด ๋ณ€๊ฒฝ ๋  ๋•Œ๋งˆ๋‹ค ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์ง€์•Š๊ณ  ํ•จ์ˆ˜์˜ ์ƒˆ๋กœ์šด ๋ฒ„์ „์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

useCallback(() => {
  return a + b
}, [a, b])

useMemo(() => {
  return () => a + b
}, [a, b])

์œ„ ์ฝ”๋“œ์—์„œ useCallback๊ณผ useMemo๋Š” ๋™์ผํ•œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜์ง€๋งŒ, useCallback์€ ์ „๋‹ฌ๋œ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ  useMemo๋Š” ์ „๋‹ฌ๋œ ํ•จ์ˆ˜์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.


๋˜ํ•œ useMemo์™€ useCallback์€ referential equality๋ฅผ ์œ ์ง€ํ•˜๊ธฐ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค.

function Parent() {
  const [items, setItems] = useState([])
  const handleLoad = (res) => setItems(res)

  return <Child onLoad={handleLoad} />
}

function Child({ onLoad }) {
  useEffect(() => {
    callApi(onLoad)
  }, [onLoad])
}

์œ„ ์˜ˆ์ œ์—์„œ handleLoad ํ•จ์ˆ˜๋Š” Parent ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง ๋  ๋•Œ๋งˆ๋‹ค re-create๋œ๋‹ค. ์ด๊ฒƒ์€ onLoad ํ•จ์ˆ˜๊ฐ€ ๋งค ๋ Œ๋”๋ง๋งˆ๋‹ค ๋‹ค๋ฅธ referential equality๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— Child ์ปดํฌ๋„ŒํŠธ์˜ useEffect๊ฐ€ ์žฌ์‹คํ–‰๋œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

function Parent() {
  const [items, setItems] = useState([])
  const handleLoad = useCallback((res) => setItems(res), [])

  return <Child onLoad={handleLoad} />
}

function Child({ onLoad }) {
  useEffect(() => {
    callApi(onLoad)
  }, [onLoad])
}

handleLoad์— useCallback๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ handleLoad ํ•จ์ˆ˜๋Š” ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๊ณ , Child ์ปดํฌ๋„ŒํŠธ์˜ useEffect๋„ ๋ Œ๋”๋ง ๋ ๋•Œ๋งˆ๋‹ค ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค.



useRef

useRef๋Š” DOM ์š”์†Œ์— ์ง์ ‘ ์ ‘๊ทผํ•˜๊ณ  ์กฐ์ž‘ํ•˜๋Š”๋ฐ ์œ ์šฉํ•œ hook์ด๋‹ค. ๋˜ํ•œ ๋ Œ๋”๋ง๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.


useRef๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„  ๋จผ์ € ref๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด์•ผํ•œ๋‹ค.

useRef(initialValue)

useRef๋Š” current๋ผ๋Š” ๋‹จ์ผ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”๋ฐ ์ดˆ๊ธฐ๊ฐ’์„ current ํ”„๋กœํผํ‹ฐ์— ํ• ๋‹นํ•œ๋‹ค.

const myRef = useRef(0);

console.log(myRef);
// { current: 0 }

useRef๋Š” ์„ ์–ธํ›„ ๋‹ค์‹œ ๋ Œ๋”๋ง์ด ๋˜์–ด๋„ ๋™์ผํ•œ ์ฐธ์กฐ๊ฐ€ ์ง€์†๋œ๋‹ค. ๋˜ํ•œ ์ฐธ์กฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด๋„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ฆ‰, ref๋Š” ๋ Œ๋”๋ง๊ฐ„์˜ ์ง€์†๋˜๋Š” ๊ฐ’์„ ์ €์žฅํ•˜๋Š” ๊ฐ์ฒด์ด๋‹ค.

function State() {
  const [rerenderCount, setRerenderCount] = useState(0);

  useEffect(() => {
    setRerenderCount(prevCount => prevCount + 1);
  });

  return <div>{rerenderCount}</div>;
}
function Ref() {
  const rerenderCount = useRef(0);

  useEffect(() => {
    rerenderCount.current = rerenderCount.current + 1;
  });

  return <div>{rerenderCount.current}</div>;
}

State ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” state๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜๋ฉด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋‹ค์‹œ ๋ Œ๋”๋ง๋˜์ง€๋งŒ Ref ์ปดํฌ๋„ŒํŠธ์˜ ref๋Š” ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์–ด๋„ ๋‹ค์‹œ ๋ Œ๋”๋ง๋˜์ง€์•Š๋Š”๋‹ค.


How to use Refs

ref๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ DOM ์š”์†Œ๋ฅผ ์ฐธ์กฐํ• ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ฒ„ํŠผ์„ ํด๋ฆญํ•  ๋•Œ๋งˆ๋‹ค input ์š”์†Œ์— ์ปค์„œ๋ฅผ ์ด๋™ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ref๋ฅผ ์‚ฌ์šฉํ•ด ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

function Component() {
  const inputRef = useRef(null)

  const focusInput = () => {
    inputRef.current.focus()
  }

  return (
    <>
      <input ref={inputRef} />
      <button onClick={focusInput}>Focus Input</button>
    </>
  )
}

Using Refs beyond the DOM

ref๋Š” ๋ Œ๋”๋ง๊ฐ„ ์ผ์ข…์˜ ์ €์žฅ๊ณต๊ฐ„์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

unction Component() {
  const [name, setName] = useState('Kyle')
  const previousName = useRef(null)

  useEffect(() => {
    previousName.current = name
  }, [name])

  return (
    <>
      <input value={name} onChange={e => setName(e.target.value)} />
      <div>{previousName.current} => {name}</div>
    </>
  )
}

์œ„ย ์˜ˆ์ œ๋Š” ์ƒํƒœ ๋ณ€์ˆ˜ name์ดย ๋ณ€๊ฒฝ๋  ๋•Œ ๋งˆ๋‹ค ref๋ฅผ ์—…๋ฐ์ดํŠธ ํ•ด ์ƒํƒœ ๋ณ€์ˆ˜ name์˜ย ์ด์ „ ๊ฐ’์„ ์ €์žฅํ•˜๋„๋ก ํ•˜๋Š” ์ฝ”๋“œ์ด๋‹ค.



useContext

What is Context API?

๋ฆฌ์•กํŠธ์—์„œ state๋Š” ๋ฐ์ดํ„ฐ์™€ props๋ฅผ ์ €์žฅํ•˜๊ณ  ์ปดํฌ๋„ŒํŠธ๋“ค๊ฐ„์˜ ๋ฐ์ดํ„ฐ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋งŽ์€ ์ปดํฌ๋„ŒํŠธ๋“ค์ด ์ค‘์ฒฉ๋œ ๊ตฌ์กฐ์—์„œ state๋ฅผ ์ „๋‹ฌํ•˜๋ ค๋ฉด ๋ณต์žกํ•œ ๋‹จ๊ณ„๋ฅผ ์—ฌ๋Ÿฌ๋ฒˆ ๊ฑฐ์ณ์•ผํ•ด ์œ ์ง€๋ณด์ˆ˜์— ์–ด๋ ค์›€์ด ์žˆ๋‹ค.

Context API๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•  ํ•„์š”์—†์ด Context ๋‚ด ์ค‘์ฒฉ๋œ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๋ฐ์ดํ„ฐ๋Š” Context ๋‚ด๋ถ€ ์–ด๋””์—์„œ๋‚˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” semi-global state์ธ ๊ฒƒ์ด๋‹ค.


const ThemeContext = React.createContext()

function App() {
  const [theme, setTheme] = useState('dark')

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <ChildComponent />
    </ThemeContext.Provider>
  )
}
function ChildComponent() {
  return <GrandChildComponent />
}
class GrandChildComponent {
  render() {
    return (
      <ThemeContext.Consumer>
        {({ theme, setTheme }) => {
          return (
            <>
              <div>The theme is {theme}</div>
              <button onClick={() => setTheme('light')}>
                Change To Light Theme
              </button>
            </>
          )
        }}
      </ThemeContext.Consumer>
    )
  }
}

์œ„ ์ฝ”๋“œ์—์„œ React.createContext๋ฅผ ์‚ฌ์šฉํ•ด ๋‘ ๋ถ€๋ถ„์„ ๊ฐ€์ง„ ๋ณ€์ˆ˜๋ฅผ ์ƒ์„ฑํ–ˆ๋‹ค.

์ฒซ๋ฒˆ์งธ ๋ถ€๋ถ„์€ ์ค‘์ฒฉ๋œ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋“ค์— ๊ฐ’์„ ์ œ๊ณตํ•˜๋Š” provider์ด๋‹ค. ์œ„ ์ฝ”๋“œ์˜ ๊ฒฝ์šฐ theme ๋ฐ setTheme์ด ์žˆ๋Š” ๋‹จ์ผ ๊ฐ์ฒด์ด๋‹ค.

๋‘๋ฒˆ์งธ ๋ถ€๋ถ„์€ consumer์ด๋‹ค. consumer์—์„œ Context์˜ ๊ฐ’์— ์•ก์„ธ์Šคํ•˜๋ ค๋ฉด ์ฝ”๋“œ๋ฅผ ๋ž˜ํ•‘ํ•ด์•ผํ•œ๋‹ค. ๋ž˜ํ•‘๋œ ์ปดํฌ๋„ŒํŠธ ์ž์‹์š”์†Œ์ธ ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ Context ๊ฐ’์„ ์ œ๊ณตํ•œ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๋‘๋ฒˆ์งธ ๋ถ€๋ถ„์—์„œ Context์˜ ๊ฐ’์„ ์–ป๊ธฐ์œ„ํ•ด ํ•จ์ˆ˜๋ฅผ ํฌํ•จํ•œ ์ปดํฌ๋„ŒํŠธ์— JSX๋ฅผ ๋ž˜ํ•‘์„ํ•จ์œผ๋กœ์จ ์ฝ”๋“œ ์ค‘์ฒฉ ๋ฐ ๋ณต์žกํ•œ ๋ ˆ์ด์–ด๋“ค์ด ์ถ”๊ฐ€๋œ๋‹ค๋Š” ๋ฌธ์ œ์ ์ด ์žˆ๋‹ค.


useContext

useContext๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ Context๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ์œ„ํ•ด consumer์—์„œ JSX ์ฝ”๋“œ๋ฅผ ๋ž˜ํ•‘ํ•  ํ•„์š” ์—†์ด Context๋ฅผ useContext hook์— ์ „๋‹ฌํ•œ๋‹ค.

function GrandChildComponent() {
  const { theme, setTheme } = useContext(ThemeContext)

  return (
    <>
      <div>The theme is {theme}</div>
      <button onClick={() => setTheme('light')}>
        Change To Light Theme
      </button>
    </>
  )
}

useContext๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ๊ธฐ์กด consumer ๋ถ€๋ถ„์˜ ๋ณต์žกํ•œ ์ค‘์ฒฉ์„ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด์ œ Context๋Š” Context๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ผ๋ฐ˜ ํ•จ์ˆ˜์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๋ฉฐ Context ๋‚ด๋ถ€์˜ ๊ฐ’์„ ์ œ๊ณตํ•œ๋‹ค. useContext์˜ provider๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์€ ๊ธฐ์กด Context API์—์„œ์™€ ์™„์ „ํžˆ ๋™์ผํ•˜๋‹ค.




Reference