React: React.memo ๋ฐ useContext ํ›…์œผ๋กœ ์žฌ๋ Œ๋”๋ง ๋ฐฉ์ง€.

์— ๋งŒ๋“  2019๋…„ 03์›” 19์ผ  ยท  37์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: facebook/react

๊ธฐ๋Šฅ ์„ ์š”์ฒญํ•˜๊ฑฐ๋‚˜ ๋ฒ„๊ทธ๋ฅผ ๋ณด๊ณ  ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

๋ฒŒ๋ ˆ

ํ˜„์žฌ ํ–‰๋™์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

React.memo์—์„œ ๋ถˆํ•„์š”ํ•œ ๋‹ค์‹œ ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด (useContext ํ›„ํฌ)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ปจํ…์ŠคํŠธ API์˜ ๋ฐ์ดํ„ฐ์— ์˜์กดํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ๋™์ž‘์ด ๋ฒ„๊ทธ์ธ ๊ฒฝ์šฐ ์žฌํ˜„ ๋‹จ๊ณ„์™€ ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ ๋ฌธ์ œ์˜ ์ตœ์†Œ ๋ฐ๋ชจ๋ฅผ ์ œ๊ณตํ•˜์‹ญ์‹œ์˜ค. ์•„๋ž˜์˜ JSFiddle(https://jsfiddle.net/Luktwrdm/) ๋˜๋Š” CodeSandbox(https://codesandbox.io/s/new) ์˜ˆ์ œ์— ๋Œ€ํ•œ ๋งํฌ๋ฅผ ๋ถ™์—ฌ๋„ฃ์Šต๋‹ˆ๋‹ค.

React.memo(() => {
const [globalState] = useContext(SomeContext);

render ...

}, (prevProps, nextProps) => {

// How to rely on context in here?
// I need to rerender component only if globalState contains nextProps.value

});

์˜ˆ์ƒ๋˜๋Š” ๋™์ž‘์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

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

์–ด๋–ค ๋ฒ„์ „์˜ React์™€ ์–ด๋–ค ๋ธŒ๋ผ์šฐ์ €/OS๊ฐ€ ์ด ๋ฌธ์ œ์˜ ์˜ํ–ฅ์„ ๋ฐ›๋‚˜์š”?
16.8.4

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

์ด๊ฒƒ์€ ์„ค๊ณ„๋œ ๋Œ€๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๊ถ๊ธˆํ•œ ์ ์ด ์žˆ์œผ๋ฉด https://github.com/facebook/react/issues/14110 ์— ์ด์— ๋Œ€ํ•œ ๋” ๊ธด ํ† ๋ก ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์–ด๋–ค ์ด์œ ๋กœ ๊ฐ’์— theme ์†์„ฑ์ด ์žˆ๋Š” AppContext ๊ฐ€ ์žˆ๊ณ  appContextValue.theme ๋ณ€๊ฒฝ ์‹œ ์ผ๋ถ€ ExpensiveTree ๋งŒ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜๋ ค๊ณ  ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

TLDR์€ ํ˜„์žฌ๋กœ์„œ๋Š” ์„ธ ๊ฐ€์ง€ ์˜ต์…˜์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์˜ต์…˜ 1(์„ ํ˜ธ): ํ•จ๊ป˜ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ๋ถ„ํ•  ์ปจํ…์ŠคํŠธ

๋งŽ์€ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ appContextValue.theme ๊ฐ€ ํ•„์š”ํ•˜์ง€๋งŒ appContextValue ์ž์ฒด๊ฐ€ ๋„ˆ๋ฌด ์ž์ฃผ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒฝ์šฐ ThemeContext ์—์„œ AppContext ThemeContext ๋ฅผ ๋ถ„ํ• ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function Button() {
  let theme = useContext(ThemeContext);
  // The rest of your rendering logic
  return <ExpensiveTree className={theme} />;
}

์ด์ œ AppContext ๋ณ€๊ฒฝํ•ด๋„ ThemeContext ์†Œ๋น„์ž๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์„ ํ˜ธ๋˜๋Š” ์ˆ˜์ • ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ํŠน๋ณ„ํ•œ ๊ตฌ์ œ๊ธˆ์œต์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์˜ต์…˜ 2: ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋‘˜๋กœ ๋‚˜๋ˆ„๊ณ  ๊ทธ ์‚ฌ์ด์— memo ๋ฅผ ๋„ฃ์Šต๋‹ˆ๋‹ค.

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

function Button() {
  let appContextValue = useContext(AppContext);
  let theme = appContextValue.theme; // Your "selector"
  return <ThemedButton theme={theme} />
}

const ThemedButton = memo(({ theme }) => {
  // The rest of your rendering logic
  return <ExpensiveTree className={theme} />;
});

์˜ต์…˜ 3: ๋‚ด๋ถ€์— useMemo ๊ตฌ์„ฑ์š”์†Œ 1๊ฐœ

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

function Button() {
  let appContextValue = useContext(AppContext);
  let theme = appContextValue.theme; // Your "selector"

  return useMemo(() => {
    // The rest of your rendering logic
    return <ExpensiveTree className={theme} />;
  }, [theme])
}

์•ž์œผ๋กœ ๋” ๋งŽ์€ ์†”๋ฃจ์…˜์ด ์žˆ์„ ์ˆ˜ ์žˆ์ง€๋งŒ ์ด๊ฒƒ์ด ํ˜„์žฌ ์šฐ๋ฆฌ๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ž˜๋„ ์˜ต์…˜ 1์ด ๋” ์ข‹์Šต๋‹ˆ๋‹ค. ์ผ๋ถ€ ์ปจํ…์ŠคํŠธ๊ฐ€ ๋„ˆ๋ฌด ์ž์ฃผ ๋ณ€๊ฒฝ๋˜๋ฉด ๋ถ„ํ• ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  37 ๋Œ“๊ธ€

์ด๊ฒƒ์€ ์„ค๊ณ„๋œ ๋Œ€๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๊ถ๊ธˆํ•œ ์ ์ด ์žˆ์œผ๋ฉด https://github.com/facebook/react/issues/14110 ์— ์ด์— ๋Œ€ํ•œ ๋” ๊ธด ํ† ๋ก ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์–ด๋–ค ์ด์œ ๋กœ ๊ฐ’์— theme ์†์„ฑ์ด ์žˆ๋Š” AppContext ๊ฐ€ ์žˆ๊ณ  appContextValue.theme ๋ณ€๊ฒฝ ์‹œ ์ผ๋ถ€ ExpensiveTree ๋งŒ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜๋ ค๊ณ  ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

TLDR์€ ํ˜„์žฌ๋กœ์„œ๋Š” ์„ธ ๊ฐ€์ง€ ์˜ต์…˜์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์˜ต์…˜ 1(์„ ํ˜ธ): ํ•จ๊ป˜ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ๋ถ„ํ•  ์ปจํ…์ŠคํŠธ

๋งŽ์€ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ appContextValue.theme ๊ฐ€ ํ•„์š”ํ•˜์ง€๋งŒ appContextValue ์ž์ฒด๊ฐ€ ๋„ˆ๋ฌด ์ž์ฃผ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒฝ์šฐ ThemeContext ์—์„œ AppContext ThemeContext ๋ฅผ ๋ถ„ํ• ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function Button() {
  let theme = useContext(ThemeContext);
  // The rest of your rendering logic
  return <ExpensiveTree className={theme} />;
}

์ด์ œ AppContext ๋ณ€๊ฒฝํ•ด๋„ ThemeContext ์†Œ๋น„์ž๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์„ ํ˜ธ๋˜๋Š” ์ˆ˜์ • ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ํŠน๋ณ„ํ•œ ๊ตฌ์ œ๊ธˆ์œต์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์˜ต์…˜ 2: ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋‘˜๋กœ ๋‚˜๋ˆ„๊ณ  ๊ทธ ์‚ฌ์ด์— memo ๋ฅผ ๋„ฃ์Šต๋‹ˆ๋‹ค.

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

function Button() {
  let appContextValue = useContext(AppContext);
  let theme = appContextValue.theme; // Your "selector"
  return <ThemedButton theme={theme} />
}

const ThemedButton = memo(({ theme }) => {
  // The rest of your rendering logic
  return <ExpensiveTree className={theme} />;
});

์˜ต์…˜ 3: ๋‚ด๋ถ€์— useMemo ๊ตฌ์„ฑ์š”์†Œ 1๊ฐœ

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

function Button() {
  let appContextValue = useContext(AppContext);
  let theme = appContextValue.theme; // Your "selector"

  return useMemo(() => {
    // The rest of your rendering logic
    return <ExpensiveTree className={theme} />;
  }, [theme])
}

์•ž์œผ๋กœ ๋” ๋งŽ์€ ์†”๋ฃจ์…˜์ด ์žˆ์„ ์ˆ˜ ์žˆ์ง€๋งŒ ์ด๊ฒƒ์ด ํ˜„์žฌ ์šฐ๋ฆฌ๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ž˜๋„ ์˜ต์…˜ 1์ด ๋” ์ข‹์Šต๋‹ˆ๋‹ค. ์ผ๋ถ€ ์ปจํ…์ŠคํŠธ๊ฐ€ ๋„ˆ๋ฌด ์ž์ฃผ ๋ณ€๊ฒฝ๋˜๋ฉด ๋ถ„ํ• ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

ํ…Œ๋งˆ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ์ด ๋‘ ์˜ต์…˜ ๋ชจ๋‘ ์ž์‹ ๋ Œ๋”๋ง์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค.

@gaearon ๋ฒ„ํŠผ์ด ์ž์‹์ž…๋‹ˆ๊นŒ ์•„๋‹ˆ๋ฉด ๋ฒ„ํŠผ์ด ์ž์‹์„ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๊นŒ? ์ด๊ฒƒ๋“ค์ด ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉ๋˜๋Š”์ง€ ์ปจํ…์ŠคํŠธ๊ฐ€ ๋ˆ„๋ฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

unstable_Profiler ์˜ต์…˜ 2๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—ฌ์ „ํžˆ onRender ์ฝœ๋ฐฑ์„ ํŠธ๋ฆฌ๊ฑฐํ•˜์ง€๋งŒ ์‹ค์ œ ๋ Œ๋”๋ง ๋กœ์ง์€ ํ˜ธ์ถœํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋ญ”๊ฐ€ ์ž˜๋ชปํ•˜๊ณ  ์žˆ๋Š” ๊ฑด ์•„๋‹๊นŒ? ~ https://codesandbox.io/s/kxz4o2oyoo~ https://codesandbox.io/s/00yn9yqzjw

์˜ˆ์ œ๋ฅผ ๋” ๋ช…ํ™•ํ•˜๊ฒŒ ์—…๋ฐ์ดํŠธํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ถˆ์•ˆ์ •ํ•œ_ํ”„๋กœํŒŒ์ผ๋Ÿฌ ์˜ต์…˜ 2๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—ฌ์ „ํžˆ onRender ์ฝœ๋ฐฑ์„ ํŠธ๋ฆฌ๊ฑฐํ•˜์ง€๋งŒ ์‹ค์ œ ๋ Œ๋”๋ง ๋กœ์ง์€ ํ˜ธ์ถœํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋ญ”๊ฐ€ ์ž˜๋ชปํ•˜๊ณ  ์žˆ๋Š” ๊ฑด ์•„๋‹๊นŒ? https://codesandbox.io/s/kxz4o2oyoo

๊ทธ๊ฒƒ์ด ๋ฐ”๋กœ ๊ทธ ์˜ต์…˜์˜ ์š”์ ์ž…๋‹ˆ๋‹ค. :-)

์•„๋งˆ๋„ ์ด์— ๋Œ€ํ•œ ์ข‹์€ ํ•ด๊ฒฐ์ฑ…์€ ์ฃผ์–ด์ง„ ์ฝœ๋ฐฑ์ด true๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ์ปจํ…์ŠคํŠธ๋ฅผ "๊ฐ€์ ธ๊ฐ€" ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋Šฅ์„ฑ์„ ๊ฐ–๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜ˆ:
useContext(ThemeContext, (contextData => contextData.someArray.length !== 0 ));

์‹ค์ œ๋กœ ๋งŒ๋‚œ ํ›„ํฌ์˜ ์ฃผ์š” ๋ฌธ์ œ๋Š” ํ›„ํฌ ๋‚ด๋ถ€์—์„œ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ํ•˜๊ณ  ๋ฉ”๋ชจํ™”๋œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋“ฑ์ž…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด, ๊ทธ๊ฒƒ์€ ๊ตฌ์„ฑํ•  ์ˆ˜ ์—†์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

https://overreacted.io/why-isnt-xa-hook/#not -a-hook-usebailout

์˜ต์…˜ 4: ๋ฐ์ดํ„ฐ ์ „ํŒŒ์— ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋ง๊ณ  ๋ฐ์ดํ„ฐ ๊ตฌ๋…์„ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค. useSubscription์„ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค(๋ชจ๋“  ๊ฒฝ์šฐ๋ฅผ ์ปค๋ฒ„ํ•˜๊ธฐ ์œ„ํ•ด ์ž‘์„ฑํ•˜๊ธฐ ์–ด๋ ต๊ธฐ ๋•Œ๋ฌธ์—).

๋‹ค์‹œ ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.
"์žฌ๋ Œ๋”๋ง ๊ตฌ์„ฑ ์š”์†Œ์—์„œ JSX๋ฅผ ํ•œ ๋‹จ๊ณ„ ์œ„๋กœ ์ด๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๋งค๋ฒˆ ๋‹ค์‹œ ์ƒ์„ฑ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."

์ž์„ธํ•œ ์ •๋ณด๋Š” ์—ฌ๊ธฐ

์•„๋งˆ๋„ ์ด์— ๋Œ€ํ•œ ์ข‹์€ ํ•ด๊ฒฐ์ฑ…์€ ์ฃผ์–ด์ง„ ์ฝœ๋ฐฑ์ด true๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ์ปจํ…์ŠคํŠธ๋ฅผ "๊ฐ€์ ธ๊ฐ€" ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋Šฅ์„ฑ์„ ๊ฐ–๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜ˆ:
useContext(ThemeContext, (contextData => contextData.someArray.length !== 0 ));

์‹ค์ œ๋กœ ๋งŒ๋‚œ ํ›„ํฌ์˜ ์ฃผ์š” ๋ฌธ์ œ๋Š” ํ›„ํฌ ๋‚ด๋ถ€์—์„œ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ํ•˜๊ณ  ๋ฉ”๋ชจํ™”๋œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋“ฑ์ž…๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—์„œ ์ฐธ/๊ฑฐ์ง“ ๋Œ€์‹ ... ์ปจํ…์ŠคํŠธ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ€๋ถ„์ง‘ํ•ฉํ•  ์ˆ˜ ์žˆ๋Š” ID ๊ธฐ๋ฐ˜ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

const contextDataINeed = useContext(ContextObj, (state) => state['keyICareAbout'])

์—ฌ๊ธฐ์„œ useContext๋Š” ์„ ํƒ๊ธฐ fn์˜ ๊ฒฐ๊ณผ๊ฐ€ ๋™์ผํ•œ ํ•จ์ˆ˜์˜ ์ด์ „ ๊ฒฐ๊ณผ์™€ ๋™์ผํ•˜์ง€ ์•Š๋Š” ํ•œ ์ด ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ํŒ์—…๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” Facebook์ด ํ›„ํฌ์™€ ํ†ตํ•ฉํ•˜๋Š” ์†”๋ฃจ์…˜์ผ ์ˆ˜ ์žˆ์Œ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. https://blog.axlight.com/posts/super-performant-global-state-with-react-context-and-hooks/

๋‹ค์‹œ ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.
"์žฌ๋ Œ๋”๋ง ๊ตฌ์„ฑ ์š”์†Œ์—์„œ JSX๋ฅผ ํ•œ ๋‹จ๊ณ„ ์œ„๋กœ ์ด๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๋งค๋ฒˆ ๋‹ค์‹œ ์ƒ์„ฑ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."

์ž์„ธํ•œ ์ •๋ณด๋Š” ์—ฌ๊ธฐ

๋ฌธ์ œ๋Š” ์œ„์—์„œ ์•„๋ž˜๋กœ ๋‹ค์‹œ ๋ Œ๋”๋ง๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๊ตฌ์„ฑ ์š”์†Œ ํŠธ๋ฆฌ๋ฅผ ์žฌ๊ตฌ์„ฑํ•˜๋Š” ๋ฐ ๋น„์šฉ์ด ๋งŽ์ด ๋“ค ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@fuleinist ํŠน์ • ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋Œ€ํ•ด ๋งŽ์ด ๋‹จ์ˆœํ™”๋˜์—ˆ์ง€๋งŒ ๊ถ๊ทน์ ์œผ๋กœ MobX์™€ ํฌ๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. MobX๋Š” ์ด๋ฏธ ์ด์™€ ๊ฐ™์ด ์ž‘๋™ํ•˜๊ณ (ํ”„๋ก์‹œ๋„ ์‚ฌ์šฉ) ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜๊ณ  ์ƒํƒœ์˜ ํŠน์ • ๋น„ํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๋‹ค์‹œ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค.

@gaearon ๋‚ด๊ฐ€ ๋ญ”๊ฐ€๋ฅผ ๋†“์น˜๊ณ  ์žˆ๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ ๋‘ ๋ฒˆ์งธ ๋ฐ ์„ธ ๋ฒˆ์งธ ์˜ต์…˜์„ ์‹œ๋„ํ–ˆ์ง€๋งŒ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ํฌ๋กฌ ํ™•์žฅ ๋ฒ„๊ทธ์— ๋ฐ˜์‘ํ•˜๋Š”์ง€ ์•„๋‹ˆ๋ฉด ๋‹ค๋ฅธ ์บ์น˜๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ๋‘ ์ž…๋ ฅ์„ ๋ชจ๋‘ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜๋Š” ํ˜•์‹์˜ ๊ฐ„๋‹จํ•œ ์˜ˆ์ž…๋‹ˆ๋‹ค. ์ฝ˜์†”์—์„œ ๋ฉ”๋ชจ๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์ง€๋งŒ DOM์€ ํ•ญ์ƒ ๋‹ค์‹œ ๋ Œ๋”๋ง๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 1000๊ฐœ ํ•ญ๋ชฉ์„ ์‹œ๋„ํ–ˆ๋Š”๋ฐ onChange ์ด๋ฒคํŠธ๊ฐ€ ์ •๋ง ๋Š๋ ค์„œ memo()๊ฐ€ ์ปจํ…์ŠคํŠธ์™€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์กฐ์–ธ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค:

๋‹ค์Œ์€ 1000๊ฐœ ํ•ญ๋ชฉ/ํ…์ŠคํŠธ ์ƒ์ž๊ฐ€ ์žˆ๋Š” ๋ฐ๋ชจ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ ๋ฐ๋ชจ์—์„œ ๊ฐœ๋ฐœ ๋„๊ตฌ๋Š” ๋‹ค์‹œ ๋ Œ๋”๋ง์„ ํ‘œ์‹œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธํ•˜๋ ค๋ฉด ๋กœ์ปฌ์—์„œ ์†Œ์Šค๋ฅผ ๋‹ค์šด๋กœ๋“œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. https://codesandbox.io/embed/zen-firefly-d5bxk

import React, { createContext, useState, useContext, memo } from "react";

const FormContext = createContext();

const FormProvider = ({ initialValues, children }) => {
  const [values, setValues] = useState(initialValues);

  const value = {
    values,
    setValues
  };

  return <FormContext.Provider value={value}>{children}</FormContext.Provider>;
};

const TextField = memo(
  ({ name, value, setValues }) => {
    console.log(name);
    return (
      <input
        type="text"
        value={value}
        onChange={e => {
          e.persist();
          setValues(prev => ({
            ...prev,
            [name]: e.target.value
          }));
        }}
      />
    );
  },
  (prev, next) => prev.value === next.value
);

const Field = ({ name }) => {
  const { values, setValues } = useContext(FormContext);

  const value = values[name];

  return <TextField name={name} value={value} setValues={setValues} />;
};

const App = () => (
  <FormProvider initialValues={{ firstName: "Marr", lastName: "Keri" }}>
    First name: <Field name="firstName" />
    <br />
    Last name: <Field name="lastName" />
  </FormProvider>
);

export default App;

image

๋ฐ˜๋ฉด์— ์ปจํ…์ŠคํŠธ๊ฐ€ ์—†๋Š” ์ด ์ ‘๊ทผ ๋ฐฉ์‹์€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ•˜์ง€๋งŒ ๋””๋ฒ„๊ทธ์—์„œ๋Š” ์—ฌ์ „ํžˆ ์˜ˆ์ƒ๋ณด๋‹ค ๋Š๋ฆฌ์ง€๋งŒ ์ ์–ด๋„ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒƒ์€ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค.

import React, { useState, memo } from "react";
import ReactDOM from "react-dom";

const arr = [...Array(1000).keys()];

const TextField = memo(
  ({ index, value, onChange }) => (
    <input
      type="text"
      value={value}
      onChange={e => {
        console.log(index);
        onChange(index, e.target.value);
      }}
    />
  ),
  (prev, next) => prev.value === next.value
);

const App = () => {
  const [state, setState] = useState(arr.map(x => ({ name: x })));

  const onChange = (index, value) =>
    setState(prev => {
      return prev.map((item, i) => {
        if (i === index) return { name: value };

        return item;
      });
    });

  return state.map((item, i) => (
    <div key={i}>
      <TextField index={i} value={item.name} onChange={onChange} />
    </div>
  ));
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

image

@marrkeri ์ฒซ ๋ฒˆ์งธ ์ฝ”๋“œ ์กฐ๊ฐ์—์„œ ์ž˜๋ชป๋œ ๊ฒƒ์ด ๋ณด์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. dev ๋„๊ตฌ์—์„œ ๊ฐ•์กฐ ํ‘œ์‹œ๋œ ๊ตฌ์„ฑ ์š”์†Œ๋Š” ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” Field ์ด๋ฉฐ ๋ฉ”๋ชจ ๊ตฌ์„ฑ ์š”์†Œ์ด๋ฉฐ areEqual ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋Š” TextField ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

์ฝ”๋“œ์ƒŒ๋“œ๋ฐ•์Šค ์˜ˆ์ œ์˜ ์„ฑ๋Šฅ ๋ฌธ์ œ๋Š” ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” 1000๊ฐœ์˜ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ๋น„๋กฏ๋œ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ•˜๋‚˜์˜ ๊ตฌ์„ฑ ์š”์†Œ(์˜ˆ Fields ๋ฆฌํŒฉํ„ฐ๋งํ•˜๊ณ  ํ•ด๋‹น ๊ตฌ์„ฑ ์š”์†Œ(๋งต ํฌํ•จ)์—์„œ ๊ฐ ๊ฐ’์— ๋Œ€ํ•ด TextField ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

@marrkeri ์ฒซ ๋ฒˆ์งธ ์ฝ”๋“œ ์กฐ๊ฐ์—์„œ ์ž˜๋ชป๋œ ๊ฒƒ์ด ๋ณด์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. dev ๋„๊ตฌ์—์„œ ๊ฐ•์กฐ ํ‘œ์‹œ๋œ ๊ตฌ์„ฑ ์š”์†Œ๋Š” ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” Field ์ด๋ฉฐ ๋ฉ”๋ชจ ๊ตฌ์„ฑ ์š”์†Œ์ด๋ฉฐ areEqual ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋Š” TextField ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

์ฝ”๋“œ์ƒŒ๋“œ๋ฐ•์Šค ์˜ˆ์ œ์˜ ์„ฑ๋Šฅ ๋ฌธ์ œ๋Š” ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” 1000๊ฐœ์˜ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ๋น„๋กฏ๋œ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ•˜๋‚˜์˜ ๊ตฌ์„ฑ ์š”์†Œ(์˜ˆ Fields ๋ฆฌํŒฉํ„ฐ๋งํ•˜๊ณ  ํ•ด๋‹น ๊ตฌ์„ฑ ์š”์†Œ(๋งต ํฌํ•จ)์—์„œ ๊ฐ ๊ฐ’์— ๋Œ€ํ•ด TextField ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

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

image

ํ•˜๋‚˜์˜ ๊ตฌ์„ฑ ์š”์†Œ๋กœ ๋ฆฌํŒฉํ† ๋งํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ๋‘ ๋ฒˆ์งธ ์š”์ ์„ ํŒŒ์•…ํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. . ์Šค๋ƒ…์ƒท pls๋ฅผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๊ทธ๋ฆฌ๊ณ  ์—ฌ๋Ÿฌ๋ถ„์€ ์ตœ๋Œ€ ํ‘œ์‹œ ์ˆ˜์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•˜์‹ญ๋‹ˆ๊นŒ? ์ง€์—ฐ์—†์ด ๊ดœ์ฐฎ์€ ๊ฒƒ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? 1000์€ ๋งŽ์€๊ฐ€์š”?

@marrkeri ์ €๋Š” https://codesandbox.io/s/little-night-p985y ์™€ ๊ฐ™์€ ๊ฒƒ์„ ์ œ์•ˆํ–ˆ์Šต๋‹ˆ๋‹ค

์ด๊ฒƒ์ด react-redux๊ฐ€ ์•ˆ์ •์ ์ธ ์ปจํ…์ŠคํŠธ API์˜ ์ด์ ์„ ์‚ฌ์šฉ ํ•˜์ง€ ์•Š๊ณ  Hooks๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•  ๋•Œ ์ปจํ…์ŠคํŠธ์— ํ˜„์žฌ ์ƒํƒœ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์„

๊ทธ๋ž˜์„œ ์žˆ๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

์˜ต์…˜ 4: ๋ ˆ๊ฑฐ์‹œ ์ปจํ…์ŠคํŠธ ์‹œ๋Œ€์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๊ตฌ๋… ๊ธฐ๋Šฅ์„ ์ปจํ…์ŠคํŠธ ๊ฐ’์œผ๋กœ ์ „๋‹ฌ

์‚ฌ์šฉ๋ฒ•์„ ์ œ์–ดํ•˜์ง€ ์•Š๊ณ (์˜ต์…˜ 2-3์— ํ•„์š”) ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ์„ ํƒ๊ธฐ๋ฅผ ์—ด๊ฑฐํ•  ์ˆ˜ ์—†์ง€๋งŒ(์˜ต์…˜ 1์— ํ•„์š”) Hooks API๋ฅผ ๋…ธ์ถœํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ์œ ์ผํ•œ ์˜ต์…˜์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const MyContext = createContext()
export const Provider = ({children}) => (
  <MyContext.provider value={{subscribe: listener => ..., getValue: () => ...}}>
    {children}
  </MyContext.provider>
)

export const useSelector = (selector, equalityFunction = (a, b) => a === b) => {
  const {subscribe, getValue} = useContext(MyContext)
  const [value, setValue] = useState(getValue())
  useEffect(() => subscribe(state => {
      const newValue = selector(state)
      if (!equalityFunction(newValue, value) {
        setValue(newValue)
      }
  }), [selector, equalityFunction])
}

@Hypnosphi : ์šฐ๋ฆฌ๋Š” ์ปจํ…์ŠคํŠธ(v6 ๊ตฌํ˜„)์—์„œ ์Šคํ† ์–ด ์ƒํƒœ ์ „๋‹ฌ์„ ์ค‘๋‹จํ•˜๊ณ  ์ง์ ‘ ์Šคํ† ์–ด ๊ตฌ๋…(v7 ๊ตฌํ˜„)์œผ๋กœ ๋‹ค์‹œ ์ „ํ™˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ์„ฑ๋Šฅ ๋ฌธ์ œ์™€ ์ปจํ…์ŠคํŠธ๋กœ ์ธํ•œ ์—…๋ฐ์ดํŠธ๋ฅผ ๊ตฌ์ œํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. v6 ์ ‘๊ทผ ๋ฐฉ์‹์„ ๊ธฐ๋ฐ˜์œผ๋กœ React-Redux ํ›„ํฌ API๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค).

์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋‚ด ํฌ์ŠคํŠธ React-Redux์˜ ์—ญ์‚ฌ ๋ฐ ๊ตฌํ˜„์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

์Šค๋ ˆ๋“œ๋ฅผ ์ฝ์—ˆ์ง€๋งŒ ์—ฌ์ „ํžˆ ๊ถ๊ธˆํ•œ ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„์— ๋‚˜์—ด๋œ "์˜ต์…˜ 1 2 3 4" ์ปจํ…์ŠคํŠธ ๋ณ€๊ฒฝ ์‹œ ์กฐ๊ฑด๋ถ€๋กœ ๋‹ค์‹œ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ์˜ต์…˜์ด ์˜ค๋Š˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๊ณต์‹์ ์œผ๋กœ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค๋ฅธ ์ž‘์—…์ด ์ง„ํ–‰ ์ค‘์ด๊ฑฐ๋‚˜ "4๊ฐ€์ง€ ์†”๋ฃจ์…˜"์ด ์ถฉ๋ถ„ํžˆ ์ˆ˜์šฉ ๊ฐ€๋Šฅํ•œ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ๋ฉ๋‹ˆ๊นŒ?

๋‚˜๋Š” ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์— ์ผ์ง€๋งŒ ๋งŒ์ผ์„ ์œ„ํ•ด. ๋‹ค์Œ์€ _๋น„๊ณต์‹์ ์ธ_ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.
userland์˜ useContextSelector ์ œ์•ˆ ๋ฐ use-context-selector ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ.

์†”์งํžˆ ์ด๊ฒƒ์€ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์šฐ๋ฆฌ๊ฐ€ ๊ถŒ์žฅํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๊ธฐ๋Šฅ๊ณผ ํ›„ํฌ์— ์™„์ „ํžˆ ๋“ค์–ด๊ฐˆ ์ค€๋น„๊ฐ€ ๋˜์ง€ ์•Š์•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ํด๋ž˜์Šค์™€ ๋ผ์ดํ”„์‚ฌ์ดํด ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋Ÿฌํ•œ ๊ฒƒ๋“ค์„ ๊น”๋”ํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ  ์ด์ œ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ›จ์”ฌ ๋” ์ฝ๊ธฐ ์–ด๋ ค์šด ๊ตฌ๋ฌธ์ด ๋ฉ๋‹ˆ๋‹ค.

์˜ต์…˜ 3์ด ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์ž˜๋ชปํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ? https://stackblitz.com/edit/react-w8gr8z

@Martin , ๋‚˜๋Š” ๊ทธ๊ฒƒ์— ๋™์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ›„ํฌ ํŒจํ„ด์€ ์ž˜ ๊ตฌ์„ฑ๋œ ๋ฌธ์„œ์™€ ์ฝ”๋“œ๋กœ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๊ตฌ์กฐ ๋ฐ React ํด๋ž˜์Šค ๋ฐ ์ˆ˜๋ช… ์ฃผ๊ธฐ๋Š” ๋ชจ๋‘ ๊ธฐ๋Šฅ์œผ๋กœ ๋Œ€์ฒด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
๋™๋“ฑํ•œ ๊ฒƒ.

๋ถˆํ–‰ํžˆ๋„ ๋ฐ˜์‘ ํŒจํ„ด์€ ๋‹ค์Œ์„ ํ†ตํ•ด React๋กœ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
React ํด๋ž˜์Šค ๋˜๋Š” ํ›„ํฌ.

2020๋…„ 1์›” 11์ผ ํ† ์š”์ผ ์˜ค์ „ 9์‹œ 44๋ถ„ Martin Genev [email protected]
์ผ๋‹ค:

์†”์งํžˆ ์ด๊ฒƒ์€ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์•„์ง ์ค€๋น„๋˜์ง€ ์•Š์•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
์šฐ๋ฆฌ๊ฐ€ ๊ถŒ์žฅํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์™„์ „ํžˆ ๊ธฐ๋Šฅ๊ณผ ํ›„ํฌ์—. ์ˆ˜์—…๊ณผ ํ•จ๊ป˜
์ด๋Ÿฌํ•œ ๊ฒƒ๋“ค์„ ๊น”๋”ํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋Š” ๋ผ์ดํ”„์‚ฌ์ดํด ๋ฐฉ๋ฒ•์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
์ด์ œ ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ›จ์”ฌ ๋” ์ฝ๊ธฐ ์–ด๋ ค์šด ๊ตฌ๋ฌธ์ด ๋ฉ๋‹ˆ๋‹ค.

โ€”
๋‹น์‹ ์ด ์–ธ๊ธ‰๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ๋ฐ›๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ด ์ด๋ฉ”์ผ์— ์ง์ ‘ ๋‹ต์žฅํ•˜๊ณ  GitHub์—์„œ ํ™•์ธํ•˜์„ธ์š”.
https://github.com/facebook/react/issues/15156?email_source=notifications&email_token=AAI4DWUJ7WUXMHAR6F2KVXTQ5D25TA5CNFSM4G7UEEO2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63
๋˜๋Š” ๊ตฌ๋… ์ทจ์†Œ
https://github.com/notifications/unsubscribe-auth/AAI4DWUCO7ORHV5OSDCE35TQ5D25TANCNFSM4G7UEEOQ
.

@mgenev ์˜ต์…˜ 3์€ ์ž์‹์˜ ์žฌ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค( <ExpensiveTree /> , ์ด๋ฆ„ ์ž์ฒด๊ฐ€ ๋งํ•จ)

@Hypnosphi ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค, ๋งž์Šต๋‹ˆ๋‹ค.
https://stackblitz.com/edit/react-ycfyye

๋‹ค์‹œ ์ž‘์„ฑํ–ˆ๊ณ  ์ด์ œ ์‹ค์ œ ๋ Œ๋”๋ง(๋””์Šคํ”Œ๋ ˆ์ด) ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๋‹ค์‹œ ๋ Œ๋”๋ง๋˜์ง€ ์•Š์ง€๋งŒ ๋ชจ๋“  ์ปจํ…Œ์ด๋„ˆ(์—ฐ๊ฒฐ๋œ ์ปจํ…์ŠคํŠธ)๋Š” ์‚ฌ์šฉ ์ค‘์ธ์ง€ ์—ฌ๋ถ€์— ๊ด€๊ณ„์—†์ด ์ปจํ…์ŠคํŠธ์—์„œ prop์ด ๋ณ€๊ฒฝ๋  ๋•Œ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค. ์ด์ œ ๋‚ด๊ฐ€ ๋ณผ ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ์˜ต์…˜์€ ์ปจํ…์ŠคํŠธ ๋ถ„ํ• ์„ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ผ๋ถ€ ํ•ญ๋ชฉ์€ ์ง„์ •์œผ๋กœ ์ „์—ญ์ ์ด๋ฉฐ ์ตœ๊ณ  ์ˆ˜์ค€์—์„œ ๋ž˜ํ•‘๋˜๋ฉฐ ๊ทธ ์•ˆ์˜ ์†Œํ’ˆ์„ ๋ณ€๊ฒฝํ•˜๋ฉด ์ „์ฒด ์•ฑ์—์„œ ๋ชจ๋“  ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ์„ฑ๋Šฅ์— ์ข‹์„ ์ˆ˜ ์žˆ๋Š”์ง€ ์ดํ•ดํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค ...

์„ฑ๋Šฅ์ ์œผ๋กœ ์ด๊ฒƒ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ข‹์€ ์˜ˆ๊ฐ€ ์–ด๋””์— ์žˆ์Šต๋‹ˆ๊นŒ? ๊ณต์‹ ๋ฌธ์„œ๋Š” ์ •๋ง ์ œํ•œ์ ์ž…๋‹ˆ๋‹ค

๊ธฐ๋ณธ์ ์œผ๋กœ react-redux๊ฐ€ ๋‚ด๋ถ€์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๋Š” ์˜ต์…˜ 4๋ฅผ ์‹œ๋„ํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
https://github.com/facebook/react/issues/15156#issuecomment -546703046

subscribe ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋ ค๋ฉด Observables ๋˜๋Š” EventEmitter์™€ ๊ฐ™์€ ๊ฒƒ์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ๊ธฐ๋ณธ ๊ตฌ๋… ๋กœ์ง์„ ์ง์ ‘ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function StateProvider({children}) {
  const [state, dispatch] = useReducer(reducer, initialState)
  const listeners = useRef([])
  const subscribe = listener => {
    listeners.current.push(listener)
  }
  useEffect(() => {
    listeners.current.forEach(listener => listener(state)
  }, [state])

  return (
    <DispatchContext.Provider value={dispatch}>
      <SubscribeContext.Provider value={{subscribe, getValue: () => state}}>
          {children}      
      </SubscribeContext.Provider>
    </DispatchContext.Provider>
  );
}

๊ด€์‹ฌ์ด ์žˆ๋Š” ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•ด ์ด ์ฃผ์ œ์™€ ๋‹ค์†Œ ๊ด€๋ จ์ด ์žˆ๋Š” ๋‹ค์–‘ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.
https://github.com/dai-shi/will-this-react-global-state-work-in-concurrent-mode

๋‚˜์˜ ์ตœ๊ทผ ๋…ธ๋ ฅ์€ ๋‹ค๊ฐ€์˜ค๋Š” ๋™์‹œ ๋ชจ๋“œ์—์„œ ์ค‘์š”ํ•  useTransition ๋กœ ์ƒํƒœ ๋ถ„๊ธฐ ์ง€์›์„ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๊ธฐ๋ณธ์ ์œผ๋กœ React ์ƒํƒœ์™€ ์ปจํ…์ŠคํŠธ๋ฅผ ์ •์ƒ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉด OK์ž…๋‹ˆ๋‹ค. (๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด this ์™€

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค @dai-shi ๊ท€ํ•˜์˜ ํŒจํ‚ค์ง€๊ฐ€ ์ •๋ง ๋งˆ์Œ์— ๋“ค๊ณ  ์ฑ„ํƒํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

@dai-shi ์•ˆ๋…•ํ•˜์„ธ์š”, ๋ฐฉ๊ธˆ react-tracked ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐพ์•˜๊ณ  ์•ฝ์†๋Œ€๋กœ ์ปจํ…์ŠคํŠธ์˜ ์„ฑ๋Šฅ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ฉด ์ •๋ง ์ข‹์•„ ๋ณด์ž…๋‹ˆ๋‹ค. ์—ฌ์ „ํžˆ ์‹ค์ œ์ ์ด๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚ซ์Šต๋‹ˆ๊นŒ? ์—ฌ๊ธฐ์— use-reducer-async https://github.com/dai-shi/react-tracked/blob/master/examples/12_async/src/store๋กœ ๋ฏธ๋“ค์›จ์–ด ์ˆ˜์ค€์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•๋„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. useReducer ์‚ฌ์šฉํ•˜์—ฌ ๋น„์Šทํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ–ˆ์œผ๋ฉฐ ๋น„๋™๊ธฐ ๋ฏธ๋“ค์›จ์–ด์šฉ์œผ๋กœ dispatch ๋ฅผ ๋‚ด ๊ฒƒ์œผ๋กœ ๋ž˜ํ•‘ํ•˜๊ณ  Context ํ–ˆ์ง€๋งŒ ์ปจํ…์ŠคํŠธ ๋ž˜ํ•‘์œผ๋กœ ์ธํ•ด ํ–ฅํ›„ ๋ Œ๋”๋ง ์„ฑ๋Šฅ ๋ฌธ์ œ์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

@bobrosoft react-tracked ๋Š” ๊ฝค ์•ˆ์ •์ ์ž…๋‹ˆ๋‹ค(ํ™•์‹คํ•œ ํ•˜๋‚˜์˜ ๊ฐœ๋ฐœ์ž ์ œํ’ˆ์œผ๋กœ). ํ”ผ๋“œ๋ฐฑ์€ ๋งค์šฐ ํ™˜์˜ํ•˜๋ฉฐ ๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๊ฐœ์„ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” ๋ฌธ์„œํ™”๋˜์ง€ ์•Š์€ React์˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ์•ž์œผ๋กœ ๋” ๋‚˜์€ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ๋กœ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. use-reducer-async ๋Š” ๊ฑฐ์˜ ์ž˜๋ชป๋˜์ง€ ์•Š๋Š” ๊ฐ„๋‹จํ•œ ๊ตฌ๋ฌธ ์„คํƒ•๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด HoC๋Š” ๋‚˜๋ฅผ ์œ„ํ•ด ์ผํ–ˆ์Šต๋‹ˆ๋‹ค.
````
'๋ฐ˜์‘'์—์„œ React, { useMemo, ReactElement, FC } ๊ฐ€์ ธ์˜ค๊ธฐ;
'lodash/reduce'์—์„œ ์ˆ˜์ž… ๊ฐ์†Œ;

์œ ํ˜• ์„ ํƒ๊ธฐ = (์ปจํ…์ŠคํŠธ: ๋ชจ๋“ ) => ๋ชจ๋“ ;

์ธํ„ฐํŽ˜์ด์Šค ์„ ํƒ๊ธฐ ๊ฐœ์ฒด {
}

const withContext = (
๊ตฌ์„ฑ ์š”์†Œ: FC,
์ปจํ…์ŠคํŠธ: ๋ชจ๋“ ,
์„ ํƒ๊ธฐ: SelectorObject,
): FC => {
return (props: any): ReactElement => {
const ์†Œ๋น„์ž = ({ ์ปจํ…์ŠคํŠธ }: ๋ชจ๋“ ): ReactElement => {
const contextProps = ์ถ•์†Œ(
์„ ํƒ๊ธฐ,
(acc: any, selector: Selector, key: string): any => {
const ๊ฐ’ = ์„ ํƒ๊ธฐ(์ปจํ…์ŠคํŠธ);
acc[ํ‚ค] = ๊ฐ’;
๋ฐ˜ํ™˜ acc;
},
{},
);
์‚ฌ์šฉ๋ฉ”๋ชจ ๋ฐ˜ํ™˜(
(): ReactElement => ,
[...Object.values(props), ...Object.values(contextProps)],
);
};
๋ฐ˜ํ’ˆ (

{(context: any): ReactElement => }

);
};
};

๊ธฐ๋ณธ ๋‚ด๋ณด๋‚ด๊ธฐ withContext;
````

์‚ฌ์šฉ ์˜ˆ:

export default withContext(Component, Context, { value: (context): any => context.inputs.foo.value, status: (context): any => context.inputs.foo.status, });

์ด๊ฒƒ์€ redux mapStateToProps์™€ ๋™๋“ฑํ•œ ์ปจํ…์ŠคํŠธ๋กœ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

redux์˜ connect()์™€ ๊ฑฐ์˜ ์œ ์‚ฌํ•œ ์ž„์‹œ ํ•ญ๋ชฉ์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

const withContext = (
  context = createContext(),
  mapState,
  mapDispatchers
) => WrapperComponent => {
  function EnhancedComponent(props) {
    const targetContext = useContext(context);
    const { ...statePointers } = mapState(targetContext);
    const { ...dispatchPointers } = mapDispatchers(targetContext);
    return useMemo(
      () => (
        <WrapperComponent {...props} {...statePointers} {...dispatchPointers} />
      ),
      [
        ...Object.values(statePointers),
        ...Object.values(props),
        ...Object.values(dispatchPointers)
      ]
    );
  }
  return EnhancedComponent;
};

๊ตฌํ˜„ :

const mapActions = state => {
  return {};
};

const mapState = state => {
  return {
    theme: (state && state.theme) || ""
  };
};
export default connectContext(ThemeContext, mapState, mapActions)(Button);


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

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

์ฃผ์š” ์š”๊ตฌ ์‚ฌํ•ญ์€ ๋‚ด๋ถ€ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์ƒํƒœ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ถ„๊ธฐ ๋•Œ๋ฌธ์— ํšจ๊ณผ์ ์œผ๋กœ ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋ฏธ๋ฆฌ ๋ Œ๋”๋งํ•œ ๋‹ค์Œ cloneElement๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์†Œํ’ˆ์„ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ๋ถ€ ๊ตฌ์„ฑ ์š”์†Œ๋Š” ๋ Œ๋”๋ง์˜ ์ปจํ…์ŠคํŠธ์™€ ๊ด€๋ จ์ด ์—†์ง€๋งŒ "๊ฐ’์„ ์ฝ์–ด์•ผ" ํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋ฌด์—‡์„ ๋†“์น˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?
context

Context._currentValue ๋Š” ํ”„๋กœ๋•์…˜์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ์— ์•ˆ์ „ํ•ฉ๋‹ˆ๊นŒ?

๊ฐ€๋Šฅํ•œ ํ•œ ์ €๋ ดํ•˜๊ฒŒ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋Š” ์ปจํ…์ŠคํŠธ์— ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๊ตฌ๋…ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ทธ๋Ÿฐ ๋‹ค์Œ ๋‚˜๋Š” ์˜›๋‚  ๋ฐฉ์‹์œผ๋กœ ์ŠคํŒŒ๊ฒŒํ‹ฐ ์ฝ”๋“œ๋กœ ์†Œํ’ˆ์„ ์ „๋‹ฌํ•˜๊ฑฐ๋‚˜ ์—…๋ฐ์ดํŠธ์— ๋…ผ๋ฆฌ์ ์ธ ๊ฒƒ์ด ์—†์„ ๋•Œ ์—…๋ฐ์ดํŠธ ๊ตฌ๋…์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ๋ฉ”๋ชจ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฉ”๋ชจ ์†”๋ฃจ์…˜์€ ๊ตฌ์„ฑ ์š”์†Œ ๋ Œ๋”๋ง์ด ์ปจํ…์ŠคํŠธ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง€์ง€๋งŒ ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ ...

@vamshi9666 ๋งŽ์ด

https://recoiljs.org/ ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ข‹์€ ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค. React์— ํ†ตํ•ฉํ•˜๋ฉด ๊ต‰์žฅํ•  ๊ฒƒ ๊ฐ™์•„์š”.

@vamshi9666 ๋งŽ์ด

ํ•œ ๊ณณ์—์„œ๋งŒ ์‚ฌ์šฉํ–ˆ์œผ๋ฉฐ ์ดˆ๊ธฐ ๋ชฉํ‘œ๋Š” jsx์—์„œ ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ๋ถ„๋ฆฌํ•˜์ง€๋งŒ ์ƒ์šฉ๊ตฌ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋Œ์—ฐ๋ณ€์ด ๊ธฐ๋Šฅ์„ ํ™•์žฅํ–ˆ์„ ๋•Œ redux์˜ ๊ฐ์†๊ธฐ ๋ฐ ์•ก์…˜ ์ƒ์„ฑ๊ธฐ ํŒจํ„ด๊ณผ ๋งค์šฐ ์œ ์‚ฌํ•ด ๋ณด์˜€์Šต๋‹ˆ๋‹ค. ์–ด๋Š ๊ฒƒ์ด ๋” ์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ์‹ค์ œ๋กœ ์ด๋ฏธ ๊ฑฐ๊ธฐ์— ์žˆ์„ ๋•Œ ๋ฌด์–ธ๊ฐ€๋ฅผ ์žฌ๋ฐœ๋ช…ํ•  ์š”์ ์„ ๋ณด์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰