๐Ÿ‘ฉ๐Ÿป‍๐Ÿ’ป Dev/Front-End

React | Context API ๊ฐœ๋…, ์‚ฌ์šฉ๋ฒ•, ํ™œ์šฉ ๋ฐฉ๋ฒ•

yesolz 2023. 12. 15. 15:26
728x90

 

Context๋ž€? : Props Drilling์˜ ๋Œ€์•ˆ

  • Context๋Š” ์ปดํฌ๋„ŒํŠธ์—์„œ Props๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋„˜๊ฒจ์ฃผ๋Š” ๋ฐฉ์‹์ด๋‹ค.
    ํŠน์ • ๋ฐ์ดํ„ฐ๋ฅผ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ ์ „์ฒด์— ๊ฑธ์ณ ์‰ฝ๊ฒŒ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.
  • Context๋Š” Props Drilling ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด ์ค„ ์ˆ˜ ์žˆ๋‹ค.
    • Props Drilling : ์ค‘์ฒฉ๋œ ์—ฌ๋Ÿฌ ๊ณ„์ธต์˜ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ props ์ „๋‹ฌ.
    • ๋ฌธ์ œ์ : ํŠน์ • prop์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ปดํฌ๋„ŒํŠธ๋“ค์—๊ฒŒ๋„ ํ•ด๋‹น prop์„ ๋‚ด๋ ค์ฃผ์–ด์•ผ ํ•˜๋Š” ๋น„ํšจ์œจ. ๊ฐ€๋…์„ฑ ํ•˜๋ฝ. ์ปดํฌ๋„ŒํŠธ ๊ฒฐํ•ฉ๋„ ์ƒ์Šน์œผ๋กœ ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง ๋ฐœ์ƒ ๊ฐ€๋Šฅ, ์ฝ”๋“œ์˜ ๋ณต์žก๋„ ์ฆ๊ฐ€
  • context๋Š” ๋ฆฌ์•กํŠธ ๋ฒ„์ „ 16๋ถ€ํ„ฐ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฆฌ์•กํŠธ ๋‚ด์žฅ API๋กœ, ์–ด๋–ค ๋ฆฌ์•กํŠธ ํ”„๋กœ์ ํŠธ๋ผ๋„ ๋ฆฌ์•กํŠธ๋ฅผ import ํ•˜๋ฉด context๋ฅผ ๋ฐ”๋กœ ์ƒ์„ฑํ•˜๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Prop drilling

 

๋ฉ€๋ฆฌ ์žˆ๋Š” ์ž์‹ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ๋„, Context๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๊ฐ’์„ ์ „๋‹ฌํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค.

 

์‚ฌ์šฉ๋ฒ• 3์ค„ ์š”์•ฝ

  1. export const MyContext = createContext(defaultValue)์„ ์‚ฌ์šฉํ•˜์—ฌ context๋ฅผ ๋งŒ๋“ค๊ณ  ๋‚ด๋ณด๋‚ธ๋‹ค.
  2. ์ด๋ฅผ useContext(MyContext) ํ›…์— ์ „๋‹ฌํ•˜๋ฉด ๊นŠ์ด์— ์ƒ๊ด€์—†์ด ๋ชจ๋“  ํ•˜์œ„ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค.
  3. ํ•˜์œ„ ํ•ญ๋ชฉ์„ <MyContext.Provider value={...}> ๋กœ ๋ฌถ์–ด ๋ถ€๋ชจ๋กœ๋ถ€ํ„ฐ ์ œ๊ณตํ•œ๋‹ค.

 

1. context ์ƒ์„ฑ : createContext

import { createContext } from 'react';

export const LevelContext = createContext(1);

๋ฆฌ์•กํŠธ ํŒจํ‚ค์ง€์—์„œ createContext๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ๋ถˆ๋Ÿฌ์™€์„œ ๋งŒ๋“ ๋‹ค.

2. context ์‚ฌ์šฉ : useContext

export default function Heading({ level, children }) {

์œ„์™€ ๊ฐ™์ด ํ”„๋กญ์œผ๋กœ ์ „๋‹ฌ๋ฐ›๋˜ ๋ฐ์ดํ„ฐ๋ฅผ

import { useContext } from 'react';
import { LevelContext } from './LevelContext.js';

export default function Heading({ children }) {
  const level = useContext(LevelContext);
  // ...
}

import ํ•œ context๋ฅผ ํ†ตํ•ด ๊ฐ’์œผ๋กœ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค.

useContext์˜ ์ธ์ž์—๋Š” createContext๋กœ ๋งŒ๋“  LevelContext๋ฅผ ๋„ฃ๋Š”๋‹ค.

useContext : React ์ปดํฌ๋„ŒํŠธ์˜ ์ตœ์ƒ์œ„ ์ˆ˜์ค€์—์„œ ์ง์ ‘ ํ˜ธ์ถœํ•ด์•ผ ํ•˜๋Š” React์˜ ํ›… ์ค‘ ํ•˜๋‚˜์ด๋‹ค. (๋ฐ˜๋ณต๋ฌธ, ์กฐ๊ฑด๋ฌธ ๋‚ด๋ถ€ ํ˜ธ์ถœ ๋ถˆ๊ฐ€) useContext๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ React ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํŠน์ • ์ปจํ…์ŠคํŠธ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ณ ์ž ํ•œ๋‹ค๊ณ  ๋ฆฌ์•กํŠธ์—๊ฒŒ ์ „๋‹ฌํ•œ๋‹ค.

 

3. context ์ œ๊ณต : Provider

context provider๋กœ ๊ฐ์‹ธ์ค€๋‹ค.

Context ๊ฐ์ฒด ์•ˆ์—๋Š” Provider๋ผ๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋“ค์–ด์žˆ๋‹ค. ๊ทธ ์ปดํฌ๋„ŒํŠธ ๊ฐ„์— ๊ณต์œ ํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฐ’์„ value๋ผ๋Š” Props๋กœ ์„ค์ •ํ•˜๋ฉด ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋“ค์—์„œ ํ•ด๋‹น ๊ฐ’์— ๋ฐ”๋กœ ์ ‘๊ทผ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

import { LevelContext } from './LevelContext.js';

export default function Section({ level, children }) {
  return (
    <section className="section">
      <LevelContext.Provider value={level}>
        {children}
      </LevelContext.Provider>
    </section>
  );
}

section ์•ˆ์˜ ์ปดํฌ๋„ŒํŠธ๊ฐ€ LevelContext๋ฅผ ์š”์ฒญํ•œ๋‹ค๋ฉด ์ด ๋ ˆ๋ฒจ์„ ์ œ๊ณตํ•˜๋ผ๊ณ  ๋ฆฌ์•กํŠธ์—๊ฒŒ ์ง€์‹œํ•˜๊ฒŒ ๋œ๋‹ค.

์ปดํฌ๋„ŒํŠธ๋Š” ๊ทธ ์œ„์˜ UI ํŠธ๋ฆฌ์—์„œ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด <LevelContext.Provider>์˜ ๊ฐ’์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋‹ค.

 

๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ context๋ฅผ use ํ•˜๊ณ  provide ํ•˜๊ธฐ

์œ„์˜ ์˜ˆ์‹œ์—์„œ level์„ ํ”„๋กญ์œผ๋กœ ๋‚ด๋ ค์ค„ ํ•„์š” ์—†์ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

import { useContext } from 'react';
import { LevelContext } from './LevelContext.js';

export default function Section({ children }) {
  const level = useContext(LevelContext);
  return (
    <section className="section">
      <LevelContext.Provider value={level + 1}>
        {children}
      </LevelContext.Provider>
    </section>
  );
}

์ƒ์œ„ ์„น์…˜์œผ๋กœ๋ถ€ํ„ฐ level์„ ์ฝ์–ด, ์ž๋™์œผ๋กœ +1์„ ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ์ „๋‹ฌํ•ด ์ค€๋‹ค.

์ด Section ์ปดํฌ๋„ŒํŠธ๋Š” useContext(LevelContext)๋ฅผ ์‚ฌ์šฉํ•ด ํ˜„์žฌ ๋ ˆ๋ฒจ์„ ๊ฐ€์ ธ์˜จ๋‹ค. 

๋˜ํ•œ <LevelContext.Provider value={level + 1}>์„ ์‚ฌ์šฉํ•ด ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋“ค์—๊ฒŒ ์ˆ˜์ •๋œ ๋ ˆ๋ฒจ ๊ฐ’์„ ์ œ๊ณตํ•œ๋‹ค.

-> ์ปดํฌ๋„ŒํŠธ๋“ค์€ Context๋ฅผ ํ†ตํ•ด ์ž์‹ ์˜ "๊นŠ์ด"๋ฅผ ํŒŒ์•…ํ•˜๊ฒŒ ๋œ๋‹ค.

 

 

Context๋Š” ์ค‘๊ฐ„์— ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ†ต๊ณผํ•œ๋‹ค.

context ๋ฐ์ดํ„ฐ๋Š” ์ค‘๊ฐ„์— ์žˆ๋Š” ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋“ค์„ ํ†ต๊ณผํ•˜๊ณ  ์ „๋‹ฌ๋œ๋‹ค. <div> ๊ฐ™์€ ๊ธฐ๋ณธ HTML ์ปดํฌ๋„ŒํŠธ๋‚˜ ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ๋งŒ๋“  ์ปดํฌ๋„ŒํŠธ ์‚ฌ์ด์—์„œ๋„ ์ „๋‹ฌ๋œ๋‹ค.

context์˜ ์ž‘๋™ ๋ฐฉ์‹์€ CSS์˜ property inheritance์™€ ์œ ์‚ฌํ•˜๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, CSS์—์„œ <div>์— color: blue๋ฅผ ์ง€์ •ํ•˜๋ฉด, ๊ทธ ์•ˆ์— ์žˆ๋Š” ๋ชจ๋“  ์š”์†Œ๋“ค์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ด ์ƒ‰์ƒ์„ ์ƒ์†๋ฐ›์ง€๋งŒ, ๋‹ค๋ฅธ ์š”์†Œ๊ฐ€ color: green์œผ๋กœ ์ด๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œํ•  ์ˆ˜ ์žˆ๋‹ค. React์—์„œ๋„ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ œ๊ณตํ•˜๋Š” ์ปจํ…์ŠคํŠธ๋Š” ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋‹ค๋ฅธ ๊ฐ’์œผ๋กœ ์˜ค๋ฒ„๋ผ์ด๋“œํ•  ์ˆ˜ ์žˆ๋‹ค.

๋˜ํ•œ, ์„œ๋กœ ๋‹ค๋ฅธ ์ปจํ…์ŠคํŠธ๋Š” ์„œ๋กœ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œ ํ•˜์ง€ ์•Š๋Š”๋‹ค. CSS์˜ color์™€ background-color๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ์†์„ฑ์œผ๋กœ ์ž‘๋™ํ•˜๋“ฏ์ด, createContext()๋กœ ๋งŒ๋“  ๊ฐ ์ปจํ…์ŠคํŠธ๋Š” ์™„์ „ํžˆ ๋ณ„๊ฐœ์ด๋‹ค. ํ•œ ์ปดํฌ๋„ŒํŠธ๋Š” ์—ฌ๋Ÿฌ ๋‹ค๋ฅธ ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๊ฒƒ๋“ค์ด ์„œ๋กœ ๊ฐ„์„ญํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

 

ํ™œ์šฉ ์‚ฌ๋ก€

 

์ปค์Šคํ…€ Hook ๋งŒ๋“ค๊ธฐ

๋งŒ์•ฝ Context๊ฐ€ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ๋‹ค๋ฉด, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ปค์Šคํ…€ Hook์„ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋‹ค.

const MyContext = createContext();

function useMyContext() {
	return useContext(MyContext);
}

function App() {
	return (
		<MyContext.Provider value="Hello World">
			<AwesomeComponent />
		</MyContext.Provider>
	);
}

function AwesomeComponent() {
	return (
		<div>
				<FirstComponent />
				<SecondComponent />
				<ThirdComponent />
		</div>
	);
}

function FirstComponent() {
	const value = useMyContext();
	return <div>First Component says: "{value}"</div>;
}

// ...

 

 

 

createContext ํ•จ์ˆ˜ ์ธ์ž์— ๊ธฐ๋ณธ ๊ฐ’ ๋„ฃ๊ธฐ

๋งŒ์•ฝ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์—์„œ useContext๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๋ฐ, Provider ์ปดํฌ๋„ŒํŠธ๋กœ ๊ฐ์‹ธ๋Š” ๊ฒƒ์„ ๊นœ๋นกํ•œ๋‹ค๋ฉด?

value ๊ฐ’์„ ์ง€์ •ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์—, undefined๋กœ ์•„๋ฌด๊ฒƒ๋„ ๋‚˜ํƒ€๋‚˜์ง€ ์•Š๊ฒŒ ๋œ๋‹ค.

์ด๋Ÿฐ ๊ฒฝ์šฐ์— ๊ธฐ๋ณธ ๊ฐ’์„ ์„ค์ •ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, createContext ํ•จ์ˆ˜์— ์ธ์ž๋กœ ๊ธฐ๋ณธ ๊ฐ’์„ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

const MyContext = createContext('default value');

๊ธฐ๋ณธ ๊ฐ’์„ ๋ณด์—ฌ์ฃผ์ง€ ์•Š๊ณ  ์•„์˜ˆ ์˜ค๋ฅ˜๋ฅผ ๋„์šฐ๊ณ  ์‹ถ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ปค์Šคํ…€ ํ›…์„ ์ˆ˜์ •ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

const MyContext = createContext();

function useMyContext() {
	const value = useContext(MyContext);
	if (value === undefined) {
		throw new Error('useMyContext should be used within MyContext.Provider');
	}
}

 

 

Context์—์„œ ์ƒํƒœ ๊ด€๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ (์œ ๋™์ ์ธ ๊ฐ’์„ ๋‹ค๋ค„์•ผ ํ•  ๋•Œ)

์ˆซ์ž๊ฐ€ ๋ณด์ด๋Š” UI์™€ ์ˆซ์ž์— ๋ณ€ํ™”๋ฅผ ์ฃผ๋Š” UI๊ฐ€ ์™„์ „ํžˆ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ๊ณ 

์ด๋ฅผ Props๋กœ ํ•จ์ˆ˜๋‚˜ ๊ฐ’์„ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ Context๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•˜๊ธฐ

๋จผ์ €, Context์—์„œ ์œ ๋™์ ์ธ ๊ฐ’์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” Provider๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

childeren Props๋ฅผ ๋ฐ›์•„์™€์„œ CounterContext.Provider ํƒœ๊ทธ ์‚ฌ์ด์— ๋„ฃ๊ณ , ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋“ค์„ CounterProvider ์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ ๊ตฌํ˜„ํ•ด ์ฃผ๋ฉด ๋œ๋‹ค.

import {createContext} from 'react';

const CounterContext = createContext();

function CounterProvider({ childeren }) {
	return <CounterContext.Provider>{children}</CounterContext.Provider>;
}

function App() {
	return (
		<CounterProvider>
			<div>
				<Value />
				<Buttons />
			</div>
		</CounterProvider>
	);
}

๋งŒ์•ฝ ์ง€๊ธˆ๊ณผ ๊ฐ™์ด ํ•˜๋‚˜์˜ ์ƒํƒœ๋งŒ ์žˆ๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด, useState๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋งŒ๋“ค์–ด์ง„ ๊ฐ’๊ณผ ํ•จ์ˆ˜๊ฐ€ ๋“ค์–ด์žˆ๋Š” ๋ฐฐ์—ด์„ ํ†ต์งธ๋กœ value๋กœ ๋„ฃ๋Š”๋‹ค.

import { createContext, useState } from 'react';

const CounterContext = createContext();

function CounterProvider({ children }) {
	const counterState = useState(1);
	return (
		<CounterContext.Provider value={counterState}>
			{children}
		</CounterContext.Provider>
	);
}

๊ทธ๋‹ค์Œ์— useCounterState๋ผ๋Š” ์ปค์Šคํ…€ Hook์„ ๋งŒ๋“ ๋‹ค.

import { createContext, useContext, useState } from 'react';
//...
function useCounterState() {
	const value = useContext(CounterContext);
	if (value === undefined) {
		throw new Error('useCounterState should be used within CounterProvider');
	}
	return value;
}

์ด๋ ‡๊ฒŒ Hook์„ ์ค€๋น„ํ•ด์ฃผ๊ณ  ๋‚˜๋ฉด, CounterProvider์˜ ์ž์‹ ์ปดํฌ๋„ŒํŠธ ์–ด๋””์„œ๋“ ์ง€ useCounterState๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ’์„ ์กฐํšŒํ•˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

๋งŒ์•ฝ์— ๋ฐ์ดํ„ฐ๋ฅผ ์–ด๋–ป๊ฒŒ ์—…๋ฐ์ดํŠธํ• ์ง€์— ๋Œ€ํ•œ ๋กœ์ง์„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ Provider๋‹จ์—์„œ ๊ตฌํ˜„ํ•˜๊ณ  ์‹ถ์œผ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

import {createContext, useContext, useMemo, useState} from 'react';

const CounterContext = createContext();

function CounterProvider({ children }) {
	const [counter, setCounter] = useState(1);
	const actions = useMemo(
		() => ({
			increase() {
				setCounter((prev) => prev + 1);
			},
			decreaset() {
				setCounter((prev) => prev - 1);
			}
		}),
		[],
	);

	**const value = useMemo(() => [counter, actions], [counter, actions]);**
	
	return (
		<CounterContext.Provider value={value}>{children}</CounterContext.Provider>
	);
}

// ์ปค์Šคํ…€ Hook
function useCounter() {
	const value = useContext(CounterContext);
	if (value === undefined) {
		throw new Error('useCounterState should be used within CounterProvider');
	}
	rturn value;
}

function App() {
	return (
		<CounterProvider>
			<div>
				<Value />
				<Buttons />
			</div>
		</CounterProvider>
	);
}

function Value() {
	const [counter] = useCounter();
	const <h1>{counter}</h1>;
}

function Buttons() {
	const [, actions] = useCounter();

	return (
		<div>
			<button onClick={actions.increase}>+</button>
			<button onClick={actions.decrease}>-</button>
		</div>
	);
}
export default App;

์œ„ ์ฝ”๋“œ์—์„œ๋Š” actions์ด๋ผ๋Š” ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์„œ ๊ทธ ์•ˆ์— ๋ณ€ํ™”๋ฅผ ์ผ์œผํ‚ค๋Š” ํ•จ์ˆ˜๋“ค์„ ๋„ฃ์—ˆ๊ณ , ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง ๋  ๋•Œ๋งˆ๋‹ค ํ•จ์ˆ˜๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“œ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ์ฒ˜์Œ์— ํ•œ๋ฒˆ ๋งŒ๋“ค๊ณ  ๊ทธ ์ดํ›„์— ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก useMemo๋กœ ๊ฐ์‹ธ์ฃผ์—ˆ๋‹ค.

value์— ๊ฐ’์„ ๋„ฃ์–ด์ฃผ๊ธฐ ์ „์— [counter, action]์„ useMemo๋กœ ํ•œ๋ฒˆ ๊ฐ์‹ธ์ฃผ์—ˆ๋‹ค. useMemo๋กœ ๊ฐ์‹ธ์ง€ ์•Š์œผ๋ฉด CounterProvider๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง ๋  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์„ ๋งŒ๋“ค๊ธฐ ๋•Œ๋ฌธ์— useContext๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ ์ชฝ์—์„œ Context์˜ ๊ฐ’์ด ๋ฐ”๋€ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผํ•˜๊ฒŒ ๋˜์–ด ๋‚ญ๋น„ ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค.

 

 

์ƒํƒœ๊ฐ€ ๋นˆ๋ฒˆํ•˜๊ฒŒ ์—…๋ฐ์ดํŠธ๋  ๋•Œ : ๊ฐ’๊ณผ ์—…๋ฐ์ดํŠธ ํ•จ์ˆ˜๋ฅผ ๋‘ ๊ฐœ์˜ Context๋กœ ๋ถ„๋ฆฌํ•˜๊ธฐ

Context์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ์ƒํƒœ๊ฐ€ ๋นˆ๋ฒˆํ•˜๊ฒŒ ์—…๋ฐ์ดํŠธ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, ์œ„ ์ฝ”๋“œ๋งŒ์œผ๋กœ๋„ ์ถฉ๋ถ„ํ•˜์ง€๋งŒ

์ƒํƒœ๊ฐ€ ๋นˆ๋ฒˆํ•˜๊ฒŒ ์—…๋ฐ์ดํŠธ๋œ๋‹ค๋ฉด ์„ฑ๋Šฅ์ ์œผ๋กœ ์ข‹์ง€ ์•Š๋‹ค.

๋ณ€ํ™”๊ฐ€ ๋ฐ˜์˜๋˜๋Š” ๊ณณ์€ Value ์ปดํฌ๋„ŒํŠธ๋ฟ์ธ๋ฐ Buttons ์ปดํฌ๋„ŒํŠธ๋„ ๋ฆฌ๋ Œ๋”๋ง ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

Context๋ฅผ ํ•˜๋‚˜ ๋” ๋งŒ๋“ค์–ด์„œ ์ด๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

import { createContext, useContext, useMemo, useState } from 'react';

const CounterValueContext = createContext();
const CounterActionsContext = createContext();

function CounterProvider({ children }) {
  const [counter, setCounter] = useState(1);
  const actions = useMemo(
    () => ({
      increase() {
        setCounter((prev) => prev + 1);
      },
      decrease() {
        setCounter((prev) => prev - 1);
      }
    }),
    []
  );

  return (
    <CounterActionsContext.Provider value={actions}>
      <CounterValueContext.Provider value={counter}>
        {children}
      </CounterValueContext.Provider>
    </CounterActionsContext.Provider>
  );
}

function useCounterValue() {
  const value = useContext(CounterValueContext);
  if (value === undefined) {
    throw new Error('useCounterValue should be used within CounterProvider');
  }
  return value;
}

function useCounterActions() {
  const value = useContext(CounterActionsContext);
  if (value === undefined) {
    throw new Error('useCounterActions should be used within CounterProvider');
  }
  return value;
}

function App() {
  return (
    <CounterProvider>
      <div>
        <Value />
        <Buttons />
      </div>
    </CounterProvider>
  );
}

function Value() {
  console.log('Value');
  const counter = useCounterValue();
  return <h1>{counter}</h1>;
}
function Buttons() {
  console.log('Buttons');
  const actions = useCounterActions();

  return (
    <div>
      <button onClick={actions.increase}>+</button>
      <button onClick={actions.decrease}>-</button>
    </div>
  );
}

export default App;

๊ธฐ์กด์˜ CounterContext๋ฅผ CounterValueContext์™€ CounterActionsContext๋กœ ๋ถ„๋ฆฌํ•ด ์ฃผ๊ณ , ๋‘ Provider๋ฅผ ๋ชจ๋‘ ์‚ฌ์šฉํ•˜๊ณ  ์ปค์Šคํ…€ Hook ๋˜ํ•œ ๋‘ ๊ฐœ๋กœ ๋ถ„๋ฆฌ.

์ด์ œ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์„œ ์ƒํƒœ์— ๋ณ€ํ™”๊ฐ€ ์ผ์–ด๋‚  ๋•Œ, Value ์ปดํฌ๋„ŒํŠธ์—์„œ๋งŒ ๋ฆฌ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•œ๋‹ค.

์œ„์—์„œ๋Š” ์ƒํƒœ๋ฅผ ๋‹ค๋ฃจ๋Š” Context๋ฅผ ํ™œ์šฉํ•˜๋Š” ๊ณผ์ •์—์„œ ์—ฌ๋Ÿฌ ์—…๋ฐ์ดํŠธ ํ•จ์ˆ˜๊ฐ€ ๋“ค์–ด์žˆ๋Š” actions ๊ฐ์ฒด๋ฅผ ์„ ์–ธํ•˜์—ฌ ๋ณ„๋„์˜ Context์— ๋„ฃ์–ด์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„์„ ํ•ด์ฃผ์—ˆ๋‹ค.

์ด ๋ฐฉ์‹ ์™ธ์—๋„, useReducer๋ฅผ ํ†ตํ•ด์„œ ์ƒํƒœ ์—…๋ฐ์ดํŠธ๋ฅผ ํ•˜๋„๋ก ๊ตฌํ˜„ํ•˜๊ณ  dispatch๋ฅผ ๋ณ„๋„์˜ Context๋กœ ๋„ฃ์–ด์ฃผ๋Š” ๋ฐฉ์‹๋„ ์žˆ๋‹ค.

์ฐธ๊ณ  : ์•„๋ž˜ ๋งํฌ

How to use React Context effectively

 

 

Context์˜ ์ƒํƒœ์—์„œ ๋ฐฐ์—ด์ด๋‚˜ ๊ฐ์ฒด๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ฒฝ์šฐ

ํ™”๋ฉด์˜ ์ค‘์•™์— ๋ฌธ๊ตฌ๋ฅผ ๋„์šฐ๋Š” ๋ชจ๋‹ฌ์˜ ์ƒํƒœ๋ฅผ Context๋กœ ์ž‘์„ฑํ•œ๋‹ค๋ฉด, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

const ModalValueContext = createContext();
const ModalActionsContext = createContext();

function ModalProvider({ children }) {
  const [modal, setModal] = useState({
    visible: false,
    message: ''
  });

  const actions = useMemo(
    () => ({
      open(message) {
        setModal({
          message,
          visible: true
        });
      },
      close() {
        setModal((prev) => ({
          ...prev,
          visible: false
        }));
      }
    }),
    []
  );

  return (
    <ModalActionsContext.Provider value={actions}>
      <ModalValueContext.Provider value={modal}>
        {children}
      </ModalValueContext.Provider>
    </ModalActionsContext.Provider>
  );
}

function useModalValue() {
  const value = useContext(ModalValueContext);
  if (value === undefined) {
    throw new Error('useModalValue should be used within ModalProvider');
  }
  return value;
}

function useModalActions() {
  const value = useContext(ModalActionsContext);
  if (value === undefined) {
    throw new Error('useModalActions should be used within ModalProvider');
  }
  return value;
}

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์›ํ•˜๋Š” ๊ณณ ์–ด๋””์„œ๋“ ์ง€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ชจ๋‹ฌ์„ ๋„์šธ ์ˆ˜ ์žˆ๋‹ค!

const { open } = useModalActions();

const handleSomething = () => {
	open('์•ˆ๋…•!');
};

๋งŒ์•ฝ ํ•  ์ผ ๋ชฉ๋ก ๊ฐ™์€ ๋ฐฐ์—ด์ด๋ผ๋ฉด?

import { createContext, useContext, useMemo, useRef, useState } from 'react';

const TodosValueContext = createContext();
const TodosActionsContext = createContext();

function TodosProvider({ children }) {
  const idRef = useRef(3);
  const [todos, setTodos] = useState([
    {
      id: 1,
      text: '๋ฐฅ๋จน๊ธฐ',
      done: true
    },
    {
      id: 2,
      text: '์ž ์ž๊ธฐ',
      done: false
    }
  ]);

  const actions = useMemo(
    () => ({
      add(text) {
        const id = idRef.current;
        idRef.current += 1;
        setTodos((prev) => [
          ...prev,
          {
            id,
            text,
            done: false
          }
        ]);
      },
      toggle(id) {
        setTodos((prev) =>
          prev.map((item) =>
            item.id === id
              ? {
                  ...item,
                  done: !item.done
                }
              : item
          )
        );
      },
      remove(id) {
        setTodos((prev) => prev.filter((item) => item.id !== id));
      }
    }),
    []
  );

  return (
    <TodosActionsContext.Provider value={actions}>
      <TodosValueContext.Provider value={todos}>
        {children}
      </TodosValueContext.Provider>
    </TodosActionsContext.Provider>
  );
}

function useTodosValue() {
  const value = useContext(TodosValueContext);
  if (value === undefined) {
    throw new Error('useTodosValue should be used within TodosProvider');
  }
  return value;
}

function useTodosActions() {
  const value = useContext(TodosActionsContext);
  if (value === undefined) {
    throw new Error('useTodosActions should be used within TodosProvider');
  }
  return value;
}

ํ•  ์ผ ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•  ๋•Œ๋Š”

const { add } = useTodosActions();

const handleSubmit = () => {
  add(text);
}

๊ฐ ํ•ญ๋ชฉ์„ ๋ณด์—ฌ์ฃผ๋Š” ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š”

const { toggle, remove } = useTodosActions()

const handleToggle = () => {
	toggle(id);
};

const handleRemove = () => {
	remove(id);
};

๊ณผ๊ฑฐ์—๋Š” ์œ„์™€ ๊ฐ™์€ ์ž‘์—…์„ ํ•˜๊ธฐ ์œ„ํ•˜์—ฌ useReducer์„ ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํ–ˆ์ง€๋งŒ, ์•ก์…˜/๋ฆฌ๋“€์„œ ๋ฐฉ์‹ ๊ตณ์ด? ์œ„์™€ ๊ฐ™์€ ๋ฐฉ์‹์ด ๋” ํŽธํ•  ๊ฑฐ๋‹ค.

 

 

Context๊ฐ€ ๊ผญ ์ „์—ญ์ ์ผ ํ•„์š”๋Š” ์—†๋‹ค.

Context์—์„œ ๋‹ค๋ฃจ๋Š” ๊ฐ’์€ ๊ผญ ์ „์—ญ์ ์ผ ํ•„์š”๊ฐ€ ์—†๋‹ค. Context๋Š” ์žฌ์‚ฌ์šฉ์„ฑ์ด ๋†’์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค ๋•Œ๋„ ๋งค์šฐ ์œ ์šฉํ•˜๋‹ค!

import { useState } from 'react';

function Item({ active, children, onClick }) {
  const activeStyle = {
    backgroundColor: 'black',
    color: 'white'
  };
  const style = {
    cursor: 'pointer',
    padding: '1rem'
  };
  return (
    <div
      style={active ? { ...style, ...activeStyle } : style}
      onClick={onClick}
    >
      {children}
    </div>
  );
}

function App() {
  const [activeId, setActiveId] = useState(1);
  return (
    <div>
      <Item active={activeId === 1} onClick={() => setActiveId(1)}>
        Hello
      </Item>
      <Item active={activeId === 2} onClick={() => setActiveId(2)}>
        World
      </Item>
      <Item active={activeId === 3} onClick={() => setActiveId(3)}>
        React
      </Item>
    </div>
  );
}

export default App;

active ๊ฐ’์„ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๊ฐ ์ปดํฌ๋„ŒํŠธ๋งˆ๋‹ค id๋ฅผ ๋น„๊ตํ•˜๊ณ , onClick๋„ ๊ฐ id์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ์ƒˆ๋กœ์šด ํ•จ์ˆ˜๋ฅผ ์„ ์–ธํ•˜์—ฌ ์„ค์ •ํ•ด ์ฃผ์—ˆ๋‹ค.

์ด๊ฑธ ์•„์˜ˆ id๋ฅผ Props๋กœ ๋„ฃ๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ฆฌํŒฉํ† ๋ง์„ ํ•œ๋‹ค๊ณ  ํ•ด๋„ ์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉ ์‹œ ๊ฐ€๋…์„ฑ์ด ๊ทธ๋ฆฌ ๋งŒ์กฑ์Šค๋Ÿฝ์ง„ ์•Š๋‹ค.

import { useState } from 'react';

function Item({ activeId, children, onSelect, id }) {
  const activeStyle = {
    backgroundColor: 'black',
    color: 'white'
  };
  const style = {
    cursor: 'pointer',
    padding: '1rem'
  };
  const active = activeId === id;
  const onClick = () => onSelect(id);
  return (
    <div
      style={active ? { ...style, ...activeStyle } : style}
      onClick={onClick}
    >
      {children}
    </div>
  );
}

function App() {
  const [activeId, setActiveId] = useState(1);
  return (
    <div>
      <Item id={1} activeId={activeId} onSelect={setActiveId}>
        Hello
      </Item>
      <Item id={2} activeId={activeId} onSelect={setActiveId}>
        World
      </Item>
      <Item id={3} activeId={activeId} onSelect={setActiveId}>
        React
      </Item>
    </div>
  );
}

export default App;

์‚ฌ์šฉํ•  ๋•Œ๋งˆ๋‹ค activeId, onSelect Props๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋„ฃ์–ด์ค˜์•ผ ํ•˜๋Š” ๊ฒŒ ์ข€ ๋ถˆํŽธํ•˜๋‹ค.

๋ฌผ๋ก  ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฐฐ์—ด์˜ map ๋‚ด์žฅํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๋ฐ˜๋ณต๋˜๋Š” ์ฝ”๋“œ๋Š” ์‚ฌ๋ผ์ง€๊ฒ ์ง€๋งŒ, ํ•ญ๋ชฉ๋“ค์„ JSX๋กœ ๋ช…๋ฃŒํ•˜๊ฒŒ ํ‘œํ˜„ํ•ด๋‚ด์ง€ ๋ชปํ•œ๋‹ค๋Š” ์ ์ด ์•„์‰ฌ์šธ ์ˆ˜๋„ ์žˆ๋‹ค.

function App() {
  const [activeId, setActiveId] = useState(1);
  const items = [
    { id: 1, text: 'Hello' },
    { id: 2, text: 'World' },
    { id: 3, text: 'React' }
  ];
  return (
    <div>
      {items.map((item) => (
        <Item
          key={item.id}
          id={item.id}
          activeId={activeId}
          onSelect={setActiveId}
        >
          {item.text}
        </Item>
      ))}
    </div>
  );
}

 

 

→ Context์˜ ํ•ด๊ฒฐ์ฑ…!

๋งŒ์•ฝ์— ํ•ญ๋ชฉ๋“ค์„ JSX๋กœ ํ‘œํ˜„ํ•˜๊ณ  ์‹ถ๊ณ , ๋ฐ˜๋ณต๋˜๋Š” ์ฝ”๋“œ๋“ค์„ ์ •๋ฆฌํ•ด์ฃผ๊ณ  ์‹ถ๋‹ค๋ฉด, ์ด ๋˜ํ•œ Context๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‰ฝ๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค!

import { createContext, useContext, useMemo, useState } from 'react';

const ItemGroupContext = createContext();
function ItemGroup({ children, activeId, onSelect }) {
  const value = useMemo(
    () => ({
      activeId,
      onSelect
    }),
    [activeId, onSelect]
  );
  return (
    <ItemGroupContext.Provider value={value}>
      {children}
    </ItemGroupContext.Provider>
  );
}
function useItemGroup() {
  const value = useContext(ItemGroupContext);
  if (value === undefined) {
    throw new Error('Item component should be used within ItemGroup');
  }
  return value;
}

function Item({ children, id }) {
	const activeStyle = {
		backgroundColor: 'black',
		color: 'white'
	};
	const style = {
		cursor: 'pointer',
		padding: '1rem'
	};
	const { activeId,onSelect } = useItemGroup();
	const active = activeId === id;
	const onClick = () => onSelect(id);
	return (
		<div
			style={active ? { ...style, ...activeStyle } : style}
			onClick={onClick}
		>
			{children}
		</div>
	);
}

function App() {
	const [activeId, setActiveId] = useState(1);
	const [anotherActiveId, setAnotherActiveId] = useState(4);

	return (
		<div>
			<ItemGroup activeId={activeId} onSelect={setActiveId}>
				<Item id={1}>Hello</Item>
				<Item id={2}>World</Item>
				<Item id={3}>React</Item>
			</ItemGroup>
			<hr />
			<ItemGroup activeId={anotherActiveId} onSelect={setAnotherActiveId}>
				<Item id={4}>Bye</Item>
        <Item id={5}>World</Item>
        <Item id={6}>Context</Item>
      </ItemGroup>
    </div>
	);
}

export default App;

ํ•„์š”ํ•œ ๊ฐ’๊ณผ ํ•จ์ˆ˜๋ฅผ ๋งค๋ฒˆ Props๋กœ ๋„ฃ์–ด์ฃผ๋Š” ๋Œ€์‹ , ItemGroup์ด๋ผ๋Š” Provider ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค์–ด์„œ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์—๋งŒ ํ•œ๋ฒˆ ๋„ฃ์–ด์ฃผ๊ณ , Item์—์„œ Context๋ฅผ ์ฝ์–ด์™€์„œ ๊ฐ’์„ ์‚ฌ์šฉํ•˜๋„๋ก ๋งŒ๋“ค์–ด์ฃผ์—ˆ๋‹ค.

๋น„๋ก ์ž‘์„ฑํ•ด์•ผ ํ•  ์ „์ฒด์ ์ธ ์ฝ”๋“œ๋Š” ์กฐ๊ธˆ ๋Š˜์—ˆ์ง€๋งŒ, Item ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ชฝ์—์„œ๋Š” ํ›จ์”ฌ ๊ฐ€๋…์„ฑ ๋†’๊ณ  ํŽธํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ณ  ์žฌ์‚ฌ์šฉ์„ฑ ๋˜ํ•œ ์ข‹์•„์กŒ๋‹ค.

์ด๋ ‡๊ฒŒ, Context๋ฅผ ๊ผญ ์ „์—ญ์ ์ธ ๊ฐ’์„ ์œ„ํ•ด์„œ๋งŒ ์“ฐ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ Props๊ฐ€ ์•„๋‹Œ ๋˜ ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด๋ผ๋Š” ์ ‘๊ทผ์„ ํ•˜์—ฌ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๋‹ค์–‘ํ•œ ์ƒํ™ฉ์— ์œ ์šฉํ•˜๊ฒŒ ์“ธ ์ˆ˜ ์žˆ๋‹ค!

 

 

์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์–ธ์ œ?

๊ณผ๊ฑฐ์—๋Š” ๋ฆฌ์•กํŠธ์˜ Context๊ฐ€ ๊ต‰์žฅํžˆ ๋ถˆํŽธํ•ด์„œ ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋‹น์—ฐ์‹œ ์—ฌ๊ฒจ์ง€๊ณค ํ–ˆ์ง€๋งŒ ์ด์ œ๋Š” ์‚ฌ์šฉํ•˜๊ธฐ ํŽธํ•ด์ ธ์„œ ๋‹จ์ˆœํžˆ ์ „์—ญ ์ƒํƒœ๋ฅผ ์œ„ํ•ด์„œ๋ผ๋ฉด ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

๋‹จ, “์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ”์™€ Context๋Š” ์™„์ „ํžˆ ๋ณ„๊ฐœ์˜ ๊ฐœ๋…์ž„์„ ์ž˜ ์•Œ์•„์•ผ ํ•œ๋‹ค. Context๋Š” ์ „์—ญ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์ˆ˜๋‹จ์ผ ๋ฟ์ด๊ณ , ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ๋”์šฑ ํŽธํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ด ์ฃผ๋Š” ๋„๊ตฌ์ด๋‹ค.

Redux

  • ์•ก์…˜๊ณผ ๋ฆฌ๋“€์„œ ๊ฐœ๋…์„ ์‚ฌ์šฉํ•˜์—ฌ ์ƒํƒœ ์—…๋ฐ์ดํŠธ ๋กœ์ง์„ ์ปดํฌ๋„ŒํŠธ ๋ฐ–์œผ๋กœ ๋ถ„๋ฆฌ
  • ์ƒํƒœ๊ฐ€ ์—…๋ฐ์ดํŠธ๋  ๋•Œ ์‹ค์ œ๋กœ ์˜์กดํ•˜๋Š” ๊ฐ’์ด ๋ฐ”๋€” ๋•Œ๋งŒ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง ๋˜๋„๋ก ์ตœ์ ํ™”
  • Context๋ฅผ ์“ด๋‹ค๋ฉด ๊ฐ๊ธฐ ๋‹ค๋ฅธ ์ƒํƒœ๋งˆ๋‹ค Context๋ฅผ ๋งŒ๋“ค์–ด์ฃผ์–ด์•ผ ํ•˜๋Š”๋ฐ ์ด ๊ณผ์ • ์ƒ๋žต ๊ฐ€๋Šฅ

MobX

  • Redux์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ƒํƒœ ์—…๋ฐ์ดํŠธ ๋กœ์ง์„ ์ปดํฌ๋„ŒํŠธ ๋ฐ–์œผ๋กœ ๋ถ„๋ฆฌ
  • ํ•จ์ˆ˜ํ˜• ๋ฆฌ์•กํŠธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹ ๋„์ž…ํ•˜์—ฌ mutable ํ•œ ์ƒํƒœ๊ฐ€ ๋ฆฌ์•กํŠธ์—์„œ๋„ ์ž˜ ๋ณด์ด๊ฒŒ ํ•˜๊ณ 
  • ์ƒํƒœ ์—…๋ฐ์ดํŠธ ๋กœ์ง์„ ๋”์šฑ ํŽธํ•˜๊ฒŒ ์ž‘์„ฑ, ์ตœ์ ํ™”๋„ ์ž˜ํ•ด์ค€๋‹ค

Recoil, Jotai, Zustand

  • Context๋ฅผ ์ผ์ผ์ด ๋งŒ๋“œ๋Š” ๊ณผ์ • ์ƒ๋žต
  • Hook ๊ธฐ๋ฐ˜์œผ๋กœ ํŽธํ•˜๊ฒŒ ์ „์—ญ ์ƒํƒœ ใ…—๊ฐ„๋ฆฌ
  • ์ตœ์ ํ™” ๊ธฐ๋Šฅ

→ ์ „์—ญ ์ƒํƒœ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๊ฒฐ๊ตญ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ์ข€ ๋” ์‰ฝ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋ฉฐ, ์ทจํ–ฅ์— ๋”ฐ๋ผ ์„ ํƒํ•ด์„œ ์“ฐ๋ฉด ๋œ๋‹ค.

 

 

 

ref

https://react.dev/learn/passing-data-deeply-with-context

 

Passing Data Deeply with Context – React

The library for web and native user interfaces

react.dev

https://velog.io/@velopert/react-context-tutorial

 

๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ์•ˆ ์•Œ๋ ค์ฃผ๋Š” ๋ฆฌ์•กํŠธ์—์„œ Context API ์ž˜ ์“ฐ๋Š” ๋ฐฉ๋ฒ•

์—ฌ๋Ÿฌ๋ถ„, ๋ฆฌ์•กํŠธ๋กœ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ ํ•˜๋ฉด์„œ Context API๋ฅผ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๊ณ  ๊ณ„์‹ ๊ฐ€์š”? ๊ณผ๊ฑฐ์—๋„ ๊ด€๋ จ ํฌ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•œ์ ์ด ์žˆ๊ธด ํ•˜์ง€๋งŒ, ์ง€๋‚œ ๋ช‡ ๋…„๊ฐ„ Context๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ ์Šต๋“ํ•˜๊ฒŒ๋œ ํŒ๋“ค์„

velog.io

 

728x90