React v18.0 (1) Automatic Batching

Janeยท2023๋…„ 11์›” 15์ผ
1

FE_Study_Notes

๋ชฉ๋ก ๋ณด๊ธฐ
1/3
post-thumbnail

2022๋…„ 3์›”์— ๋ฐœํ‘œ๋œ React 18์€ ์„ฑ๋Šฅ ํ–ฅ์ƒ๊ณผ ๋ Œ๋”๋ง ์—”์ง„ ๊ฐœ์„ ์— ์ดˆ์ ์ด ๋งž์ถฐ์ ธ ์žˆ๋‹ค.
React 18์€ ๋™์‹œ์„ฑ(concurrent) React๋ฅผ ๊ฐ•์กฐํ•˜๋ฉฐ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ๋“ค์„ ์ถœ์‹œํ•˜์˜€๋Š”๋ฐ,
ํ”„๋กœ์ ํŠธ์— ํ•ด๋‹น ๊ธฐ๋Šฅ๋“ค์„ ์ ์šฉํ•˜๊ธฐ์— ์•ž์„œ ์ด ์ค‘ ๋ช‡ ๊ฐ€์ง€ ๊ธฐ๋Šฅ๋“ค์„ ์ž์„ธํžˆ ์•Œ์•„๋ณด๊ณ ์ž ํ•œ๋‹ค.

๐Ÿค  React 18์˜ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ ์ฒซ ๋ฒˆ์งธ, Automatic Batching!

๐Ÿ‘ฉโ€๐Ÿซ React 18์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด๋‚˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ฝ”๋“œ์— ๋Œ€ํ•œ 
์ˆ˜๋™ ๋ฐฐ์น˜(batch) ์—…๋ฐ์ดํŠธ๋ฅผ ์ œ๊ฑฐํ•˜์˜€์Šต๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ์ด๋ฅผ ํ†ตํ•ด ์šฐ๋ฆฌ๋Š” ๋ณ„๋„์˜ ์„ค์น˜๋‚˜ ๊ตฌ์„ฑ ์—†์ด๋„ 
๋ฐ”๋กœ ๋” ๋งŽ์€ Batching์„ ํ†ตํ•ด ์„ฑ๋Šฅ์˜ ๊ฐœ์„ ์„ ๊ฒฝํ—˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ,, ์—ฌ๊ธฐ์„œ ๋งํ•˜๋Š” ๋ฐฐ์นญ(Batching)์ด๋ž€ ๋ญ˜๊นŒ..?

๐Ÿค” Batching์ด๋ž€ ๋ฌด์—‡์ธ๊ฐ€!

Batching

  • React๊ฐ€ ๋” ๋‚˜์€ ์„ฑ๋Šฅ์„ ์œ„ํ•ด ๋‹ค์ˆ˜์˜ ์ƒํƒœ ์—…๋ฐ์ดํŠธ๋ฅผ ํ•œ ๋ฒˆ์˜ ๋ฆฌ๋ Œ๋”๋ง์œผ๋กœ ๋ฌถ๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค.
  • ํ•˜๋‚˜์˜ ํด๋ฆญ ์ด๋ฒคํŠธ์— ๋‘ ๊ฐœ์˜ ์ƒํƒœ ์—…๋ฐ์ดํŠธ๊ฐ€ ์—ฎ์—ฌ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.
    - ์ด๋•Œ React๋Š” ํ•ญ์ƒ ์ด ๋‘ ๊ฐœ์˜ ์—…๋ฐ์ดํŠธ๋ฅผ ํ•˜๋‚˜์˜ ๋ฆฌ๋ Œ๋”๋ง์œผ๋กœ Batching ํ•œ๋‹ค.
    • ํด๋ฆญ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ๋งˆ๋‹ค ๋‘ ๊ฐœ์˜ ์ƒํƒœ ์—…๋ฐ์ดํŠธ๋ฅผ ์„ค์ •ํ•ด๋‘์–ด๋„ React๋Š” ์˜ค์ง ํ•œ ๋ฒˆ์˜ ๋ Œ๋”๋ง๋งŒ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
function App() {
  const [count, setCount] = useState(0);
  const [isOpen, setIsOpen] = useState(false);

  function handleClick() {
    setCount(prev => prev + 1); // ์•„์ง ๋ฆฌ๋ Œ๋”๋ง ๋˜์ง€ ์•Š์Œ
    setIsOpen(prev => !prev); // ์•„์ง ๋ฆฌ๋ Œ๋”๋ง ๋˜์ง€ ์•Š์Œ
    // React๋Š” ๋งˆ์ง€๋ง‰์— ํ•œ ๋ฒˆ๋งŒ ๋ฆฌ๋ Œ๋”๋งํ•œ๋‹ค!
  }

  return (
    <div>
      <button onClick={handleClick}>Next</button>
      <h1>{isOpen ? "์—ด๋ฆผ" : "๋‹ซํž˜"}</h1>
	  {isOpen && <Toggle Component/>}
    </div>
  );
}
  • ํด๋ฆญ ๋‹น ํ•œ ๋ฒˆ์˜ ๋ Œ๋”๋ง๋งŒ ๋ฐœ์ƒํ•œ๋‹ค.

๐Ÿ‘ฅ Batching์€ ์™œ ์ข‹์„๊นŒ?

  1. ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์„ ํ”ผํ•ด์„œ ์„ฑ๋Šฅ์— ์ข‹๋‹ค.
  2. ํ•˜๋‚˜์˜ ์ƒํƒœ ๋ณ€์ˆ˜๋งŒ ์—…๋ฐ์ดํŠธ ๋œ ๊ฒฝ์šฐ์— ์ปดํฌ๋„ŒํŠธ๊ฐ€ '๋ฐ˜๋งŒ ์™„๋ฃŒ๋œ' ์ƒํƒœ๋ฅผ ๋ Œ๋”๋งํ•ด ๋ฒ„๊ทธ๋ฅผ ์•ผ๊ธฐํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.
๐Ÿ‘ฉโ€๐Ÿซ ์—˜๋ฆฌ๋ฒ ์ดํ„ฐ๊ฐ€ ํ•œ ๋ช…์ด ํƒ”๋‹ค๊ณ  ๋ฐ”๋กœ ์ถœ๋ฐœํ•˜๊ณ  
๊ฐ ํƒ‘์Šน๊ฐ๋งˆ๋‹ค ๋™์ผํ•œ ์ด๋™์„ ๋ฐ˜๋ณตํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ 
ํƒ€๋ ค๋Š” ์‚ฌ๋žŒ์ด ๋ชจ๋‘ ํƒ‘์Šนํ•œ ์ดํ›„ ์ถœ๋ฐœํ•˜๋Š” ๋ชจ์Šต์„ ์ƒ์ƒํ•ด๋ด…์‹œ๋‹ค!

โš ๏ธ ๊ธฐ์กด Batching์˜ ๋ฌธ์ œ์ 

  • React์—์„œ ์—…๋ฐ์ดํŠธ๋ฅผ Batchingํ•˜๋Š” ์‹œ์ ์ด ์ผ๊ด€์ ์ด์ง€ ์•Š์•˜๋‹ค.
  • ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ฐ์ดํ„ฐ fetching์„ ํ•œ ๋’ค ํด๋ฆญ ์ด๋ฒคํŠธ ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ ์ƒํƒœ๊ฐ€ ์—…๋ฐ์ดํŠธ ๋˜๋„๋ก ํ•˜๋Š” ์ƒํ™ฉ์„ ๊ฐ€์ •ํ•ด๋ณด์ž.
    • ์ด๋•Œ React๋Š” ์—…๋ฐ์ดํŠธ๋ฅผ Batchingํ•˜์ง€ ์•Š๊ณ  ๋‘ ๊ฐœ์˜ ๋…๋ฆฝ์ ์ธ ์—…๋ฐ์ดํŠธ๋ฅผ ์‹คํ–‰ํ–ˆ๋‹ค.
      - ์ด๋Š” React๊ฐ€ ์˜ค์ง ๋ธŒ๋ผ์šฐ์ € ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๋™์•ˆ์—๋งŒ ์—…๋ฐ์ดํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ , ์ด๋ฒคํŠธ๊ฐ€ ์ด๋ฏธ ํ•ธ๋“ค๋ง ๋œ ํ›„์—๋Š” ์—…๋ฐ์ดํŠธ๋ฅผ ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•˜๋Š” ์ƒํ™ฉ์ด๋‹ค.
function App() {
  const [count, setCount] = useState(0);
  const [flag, setFlag] = useState(false);

  function handleClick() {
    fetchSomething().then(() => {
      // callback ์‹คํ–‰ ์ดํ›„์— ๋™์ž‘ํ•˜๋Š” ๋ถ€๋ถ„์ด๋ฏ€๋กœ
      // React 17 ์ด์ „์˜ ๊ฒฝ์šฐ ์ด ๋ถ€๋ถ„์€ Batching ๋˜์ง€ ์•Š์Œ
      setCount(c => c + 1); // ๋ฆฌ๋ Œ๋”๋ง ๋ฐœ์ƒ
      setFlag(f => !f); // ๋ฆฌ๋ Œ๋”๋ง ๋ฐœ์ƒ
    });
  }

  return (
    <div>
      <button onClick={handleClick}>Next</button>
      <h1 style={{ color: flag ? "blue" : "black" }}>{count}</h1>
    </div>
  );
}
  • ํด๋ฆญ ํ•  ๋•Œ๋งˆ๋‹ค ๋‘ ๊ฐœ ๋ชจ๋‘์— ๋Œ€ํ•œ ๋ Œ๋”๋ง์ด ๊ฐ๊ฐ ๋ฐœ์ƒํ•œ๋‹ค.
๐Ÿ‘ฉโ€๐Ÿซ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Automatic Batching์ด ๋“ฑ์žฅํ–ˆ์Šต๋‹ˆ๋‹ค!

๐Ÿง Automatic Batching์€ ๋ฌด์—‡์ผ๊นŒ?

  • Automatic Batching์ด ์—†์„ ๋•Œ์—๋Š” Batching์ด ์˜ค์ง React ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ๋‚ด๋ถ€์—์„œ๋งŒ ๋™์ž‘ํ–ˆ๋‹ค.
  • ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฒฝ์šฐ์—๋Š” React์—์„œ Batching์„ ๊ธฐ๋ณธ ๊ฐ’์œผ๋กœ ์ ์šฉํ•˜์ง€ ์•Š์•˜๋‹ค.
    - addEventListener()๊ณผ ๊ฐ™์€ ๊ธฐ์กด DOM ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ
    • ๋น„๋™๊ธฐ ์ฝœ๋ฐฑ (Promise, setTimeout(), setInterval() ๋“ฑ)
  • React 18์„ createRoot์™€ ํ•จ๊ป˜ ์‹œ์ž‘ํ•˜๋ฉด, ์—…๋ฐ์ดํŠธ๊ฐ€ ์–ด๋””์— ์œ„์น˜ํ•ด์žˆ๋Š”์ง€์— ๊ด€๊ณ„ ์—†์ด ๋ชจ๋‘ ์ž๋™ Batching ๋œ๋‹ค.
    - ์ด์ œ ๋ชจ๋“  ์ด๋ฒคํŠธ ๋‚ด๋ถ€์˜ ์—…๋ฐ์ดํŠธ๋Š” React ์ด๋ฒคํŠธ ๋‚ด๋ถ€์™€ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ Batching ๋œ๋‹ค.
    • ์ด๋ฅผ ํ†ตํ•ด ๋” ์ ์€ ๋นˆ๋„์˜ ๋ Œ๋”๋ง์„ ๋ฐœ์ƒ์‹œํ‚ค๊ณ , ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์„ฑ๋Šฅ์„ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.
// ์ด์ „: ์˜ค์ง React ์ด๋ฒคํŠธ์—์„œ๋งŒ Batching ์ ์šฉ
setTimeout(() => {
  setCount(prev => prev + 1);
  setFlag(prev => !prev);
  // React๋Š” ๊ฐ๊ฐ์˜ ์ƒํƒœ ์—…๋ฐ์ดํŠธ๋งˆ๋‹ค ๋ Œ๋”๋ง ๋œ๋‹ค. (์ด ๋‘ ๋ฒˆ)
}, 1000);

// ์ดํ›„: timeouts, promises ๋“ฑ ๋ชจ๋“  ์ด๋ฒคํŠธ ๋‚ด๋ถ€์—์„œ Batching ์ ์šฉ
setTimeout(() => {
  setCount(prev => prev + 1);
  setFlag(prev => !prev);
  // React๋Š” ๋งˆ์ง€๋ง‰์— ํ•œ ๋ฒˆ๋งŒ ๋ฆฌ๋ Œ๋”๋ง ๋œ๋‹ค.
}, 1000);
  • ํด๋ฆญ ์‹œ ํ•œ ๋ฒˆ์˜ ๋ Œ๋”๋ง๋งŒ ๋ฐœ์ƒํ•œ๋‹ค.

  • createRoot๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ 17 ์ดํ•˜ ๋ฒ„์ „๊ณผ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•˜๋‹ˆ ์ฃผ์˜ํ•˜์ž!

๐Ÿค” ์˜ˆ์ „์˜ ๋™์ž‘์ด ์•„์ง ๋‚จ์•„์žˆ๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ธ๊ฐ€์š”?
๐Ÿ‘ฉโ€๐Ÿซ ์ด์ „ ๋ฒ„์ „๊ณผ 18 ๋ฒ„์ „ ๋ชจ๋‘๋ฅผ ์‚ฌ์šฉํ•ด ์ˆ˜ํ–‰ ์‹คํ—˜์„ ํ•  ๊ฒฝ์šฐ์— ๋Œ€๋น„ํ•ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. 
ํ•˜์ง€๋งŒ React 18 ์‚ฌ์šฉ ์‹œ createRoot๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ 
automatic batching์ด ์ ์šฉ๋˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค. 
  • ์ด์ œ ์•„๋ž˜์˜ ์ฝ”๋“œ๋Š” ๋ชจ๋‘ ๋™์ผํ•œ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.
// (1) ํด๋ฆญ ์ด๋ฒคํŠธ
function handleClick() {
  setCount(c => c + 1);
  setFlag(f => !f);
  // ๋งจ ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์—์„œ๋งŒ ๋ฆฌ๋ Œ๋”๋ง ๋ฐœ์ƒ
}

// (2) setTimeout
setTimeout(() => {
  setCount(c => c + 1);
  setFlag(f => !f);
  // ๋งจ ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์—์„œ๋งŒ ๋ฆฌ๋ Œ๋”๋ง ๋ฐœ์ƒ
}, 1000);

// (3) Promise
fetch(/*...*/).then(() => {
  setCount(c => c + 1);
  setFlag(f => !f);
  // ๋งจ ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์—์„œ๋งŒ ๋ฆฌ๋ Œ๋”๋ง ๋ฐœ์ƒ
})

// (4) DOM ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ
elm.addEventListener('click', () => {
  setCount(c => c + 1);
  setFlag(f => !f);
  // ๋งจ ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์—์„œ๋งŒ ๋ฆฌ๋ Œ๋”๋ง ๋ฐœ์ƒ
});
  • React๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์•ˆ์ „ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์—…๋ฐ์ดํŠธ๋ฅผ Batching ํ•œ๋‹ค.
  • ์˜ˆ๋ฅผ ๋“ค์–ด, React๋Š” ๋‹ค์Œ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์ „ ํด๋ฆญ, ํ‚ค๋ณด๋“œ ์ด๋ฒคํŠธ์ฒ˜๋Ÿผ ์‚ฌ์šฉ์ž ์‹œ์ž‘ ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ DOM์„ ์™„์ „ํžˆ ์—…๋ฐ์ดํŠธํ•  ๊ฒƒ์„ ๋ณด์žฅํ•œ๋‹ค.
    - ๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์€ ์ œ์ถœ ์‹œ ๋น„ํ™œ์„ฑํ™” ๋œ form์ด ๋‘ ๋ฒˆ ์ œ์ถœ๋  ์ˆ˜ ์—†๋„๋ก ํ•˜๋Š” ๋“ฑ์˜ ํšจ๊ณผ๋ฅผ ์ค€๋‹ค.

๐Ÿ’ก FAQ

๐Ÿคทโ€โ™€๏ธ Batch๋ฅผ ์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด?

  • ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ Batching์ด ์•ˆ์ „ํ•˜๊ธด ํ•˜์ง€๋งŒ, ์ƒํƒœ๊ฐ€ ๋ณ€ํ™”ํ•˜์ž๋งˆ์ž DOM์—์„œ ๋ฌด์–ธ๊ฐ€๋ฅผ ์ฆ‰์‹œ ์ฝ์–ด์™€์•ผ ํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค๋ฉด Batching์„ ์‚ฌ์šฉํ•˜์ง€ ๋ง์•„์•ผ ํ•  ๊ฒƒ์ด๋‹ค.
  • ์ด๋Ÿด ๋•Œ๋Š” ReactDOM.flushSync() ๋ฅผ ์‚ฌ์šฉํ•ด Batching์„ ํ•ด์ œํ•  ์ˆ˜ ์žˆ๋‹ค.
    - react๊ฐ€ ์•„๋‹ˆ๋ผ 'react-dom'์—์„œ import ํ•ด์™€์•ผ ํ•œ๋‹ค!
import { flushSync } from 'react-dom'; 

function handleClick() {
  flushSync(() => {
    setCounter(c => c + 1);
  });
  // ์ด๋•Œ React๊ฐ€ DOM์„ ์—…๋ฐ์ดํŠธ ํ–ˆ๋‹ค.
  flushSync(() => {
    setFlag(f => !f);
  });
  // ์ด๋•Œ React๊ฐ€ DOM์„ ์—…๋ฐ์ดํŠธ ํ–ˆ๋‹ค.
}

๐Ÿคทโ€โ™€๏ธ ํ›… ํ•จ์ˆ˜ ์‚ฌ์šฉ์— ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ์ง„ ์•Š์„๊นŒ?

๐Ÿ‘ฉโ€๐Ÿซ ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค!
  • React ๊ฐœ๋ฐœํŒ€์—์„œ๋Š” ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ์— automatic batcing์ด '๊ทธ๋ƒฅ ์ž˜ ์ž‘๋™'ํ•  ๊ฒƒ์ด๋ผ๊ณ  ์˜ˆ์ธกํ•œ๋‹ค.

๐Ÿคทโ€โ™€๏ธ ํด๋ž˜์Šค ์‚ฌ์šฉ์— ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ์ง„ ์•Š์„๊นŒ?

๐Ÿ‘ฉโ€๐Ÿซ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ๋Š” ์˜ˆ์™ธ ์ƒํ™ฉ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค!

17์ดํ•˜ ๋ฒ„์ „์—์„œ์˜ ํด๋ž˜์Šค

ํด๋ž˜์Šค์—์„œ๋Š” setState ํ˜ธ์ถœ ์ค‘ this.state๋ฅผ ํ†ตํ•ด ์ƒํƒœ๊ฐ’์„ ๋™๊ธฐ์ ์œผ๋กœ ์ฝ์„ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

// React 17 ์ดํ•˜ ๋ฒ„์ „
handleClick = () => {
  setTimeout(() => {
    this.setState(({ count }) => ({ count: count + 1 }));

    console.log(this.state); // { count: 1, isClicked: false }

    this.setState(({ isClicked }) => ({ isClicked: !isClicked }));
  });
};

18 ๋ฒ„์ „์˜ ํด๋ž˜์Šค

ํ•˜์ง€๋งŒ ์ด๋Š” React 18์—์„œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๋ฐฉ์‹์ด ๋˜์—ˆ๋‹ค.
- setTimeout ๋‚ด๋ถ€์— ์žˆ๋Š” ์—…๋ฐ์ดํŠธ๋“ค๊นŒ์ง€ ๋ชจ๋‘ Batching๋˜๊ธฐ ๋•Œ๋ฌธ์— React๋Š” ๋”์ด์ƒ setState์˜ ๊ฒฐ๊ณผ๋ฅผ ๋™๊ธฐ์ ์œผ๋กœ ๋ Œ๋”๋งํ•˜์ง€ ์•Š๊ฒŒ ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค!

  • ๋ Œ๋”๋ง์€ ๋‹ค์Œ ๋ฒˆ ๋ธŒ๋ผ์šฐ์ € ํ‹ฑ์—์„œ ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค.
    - ํ‹ฑ: ์‹คํ–‰๋˜๋Š” ํ”„๋กœ๊ทธ๋žจ์—์„œ์˜ ๊ฐ„๊ฒฉ, ๋‚ด๋ถ€์˜ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ฐ„๊ฒฉ
// 18 ๋ฒ„์ „
handleClick = () => {
  setTimeout(() => {
    this.setState(({ count }) => ({ count: count + 1 }));

    console.log(this.state); // { count: 0, isClicked: false }

    this.setState(({ isClicked }) => ({ isClicked: !isClicked }));
  });
};
  • ์ด๋Ÿฌํ•œ ๋ฌธ์ œ ๋•Œ๋ฌธ์— 18๋ฒ„์ „์œผ๋กœ ์—…๋ฐ์ดํŠธ๋ฅผ ๋ชปํ•˜๊ณ  ์žˆ๋‹ค๋ฉด, ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ReactDOM.flushSync๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—…๋ฐ์ดํŠธ๋ฅผ ๊ฐ•์ œํ•  ์ˆ˜ ์žˆ๊ธด ํ•˜๋‹ค.
    โžก๏ธ ํ•˜์ง€๋งŒ ์‚ฌ์šฉ์„ ์ง€์–‘ํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค๊ณ  ํ•œ๋‹ค.
// 18 ๋ฒ„์ „
handleClick = () => {
  setTimeout(() => {
    ReactDOM.flushSync(() => {
      this.setState(({ count }) => ({ count: count + 1 }));
    });

    console.log(this.state); // { count: 1, isClicked: false }

    this.setState(({ isClicked }) => ({ isClicked: !isClicked }));
  });
};
  • Hooks๋ฅผ ๊ฐ€์ง„ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๋Š” ์ด๋Ÿฌํ•œ ๋ฌธ์ œ์— ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค.
    - state ๋ณ€๊ฒฝ์ด ๊ธฐ์กด ๊ฐ’์„ ์—…๋ฐ์ดํŠธํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค!

    function handleClick() {
      setTimeout(() => {
        console.log(count); // 0
        setCount(c => c + 1);
        setCount(c => c + 1);
        setCount(c => c + 1);
        console.log(count); // 0
      }, 1000)
  • setCount ํ•จ์ˆ˜๋Š” ์ด์ „ ์ƒํƒœ ๊ฐ’์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ธ์ž๋กœ ๋ฐ›๊ณ , ์ด์ „ ์ƒํƒœ ๊ฐ’์„ ์ง์ ‘ ์ฐธ์กฐํ•˜์—ฌ ์ƒˆ๋กœ์šด ์ƒํƒœ ๊ฐ’์„ ๊ณ„์‚ฐํ•˜๋Š” ํ•จ์ˆ˜ํ˜• ์—…๋ฐ์ดํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.
    - ํ•˜์ง€๋งŒ ์ด๋Ÿฌํ•œ ์ƒํƒœ ์—…๋ฐ์ดํŠธ ํ•จ์ˆ˜๋Š” ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.

    • ๋”ฐ๋ผ์„œ setCount ํ•จ์ˆ˜ ํ˜ธ์ถœ ์‹œ ๊ธฐ์กด ์ƒํƒœ ๊ฐ’์ด ์ฆ‰์‹œ ์—…๋ฐ์ดํŠธ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ํ†ตํ•ด ๋Œ€๊ธฐํ•˜๋‹ค๊ฐ€ ๋‹ค์Œ ๋ Œ๋”๋ง ์‚ฌ์ดํด์—์„œ ์—…๋ฐ์ดํŠธ ๋œ๋‹ค.
    • ๋”ฐ๋ผ์„œ setTimeout ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ ์—…๋ฐ์ดํŠธ๋“ค์€ ์•„์ง ๋ Œ๋”๋ง ์‚ฌ์ดํด์—์„œ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์•„ ๋‘ ๋ฒˆ์งธ ์ฝ˜์†”์—๋„ ์ด์ „ ์ƒํƒœ ๊ฐ’์ธ '0'์ด ์ถœ๋ ฅ๋œ๋‹ค.
  • ์œ„์˜ ์ฝ”๋“œ์—์„œ setTimeout ํ•จ์ˆ˜ ์ข…๋ฃŒ ํ›„ ์—…๋ฐ์ดํŠธ ๋œ ๊ฐ’์„ ํ™•์ธํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์œ„์˜ ๋ฐฉ์‹์œผ๋กœ ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ๋‚ด์—์„œ ์ง์ ‘ ์ƒํƒœ ๊ฐ’์„ ์ฐธ์กฐํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, useEffect ํ›…์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์ฝ˜์†”์— ๊ฐ’์ด ์ฐํžˆ๋Š” ๋ฐฉ์‹์œผ๋กœ ์ˆ˜์ •ํ•ด์•ผ ํ•  ๊ฒƒ์ด๋‹ค.

๐Ÿซต unstable_batchedUpdates๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค๋ฉด ์ฃผ๋ชฉ..!

  • ๋ช‡๋ช‡ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๊ฒฝ์šฐ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ์™ธ๋ถ€์—์„œ setState๋ฅผ ๊ฐ•์ œํ•˜๊ธฐ ์œ„ํ•ด ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฌธ์„œํ™”๋˜์ง€๋„ ์•Š์€ API๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํ–ˆ๋‹ค.

unstable_batchedUpdates

  • ์•ž์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ, 17๋ฒ„์ „ ์ดํ•˜ React์—์„œ๋Š” onClick๊ณผ ๊ฐ™์€ ๋ธŒ๋ผ์šฐ์ € ์ด๋ฒคํŠธ์—๋งŒ Batching์ด ์žˆ๊ณ  ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฒฝ์šฐ์—์„œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์—ˆ๋‹ค.
import { unstable_batchedUpdates } from 'react-dom';

const batchUpdate = unstable_batchedUpdates(() => {
  setCount((prev) => (prev) + 1);
  setFlag((prev) => !(prev));
});  

batchUpdate()
  • ์ด ํ•จ์ˆ˜๋Š” ๋‚ด๋ถ€์˜ ๋ชจ๋“  ์ƒํƒœ ๋ณ€ํ™”๋ฅผ ํ•˜๋‚˜์˜ ๊ทธ๋ฃน์œผ๋กœ ๋ฌถ๊ณ  ํ•œ ๋ฒˆ์˜ ๋ฆฌ๋ Œ๋”๋ง์—์„œ ๋ชจ๋‘ ์ ์šฉํ•œ๋‹ค.

๐Ÿ“ข ์ด์ œ๋Š” ๋ณด๋‚ด์ค์‹œ๋‹ค!

  • ์ด API๋Š” ์—ฌ์ „ํžˆ React 18 ๋ฒ„์ „์— ๋‚จ์•„์žˆ์ง€๋งŒ Batching์ด ์ž๋™์œผ๋กœ ์ด๋ฃจ์–ด์ง€๋ฏ€๋กœ ๋”์ด์ƒ ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค.
  • ๊ณต์‹ Github์— ๋”ฐ๋ฅด๋ฉด 18 ๋ฒ„์ „๊นŒ์ง€๋Š” ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ์‚ญ์ œํ•˜์ง€ ์•Š์„ ์˜ˆ์ •์ด์ง€๋งŒ, ์œ ๋ช… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด ์ด ๊ธฐ๋Šฅ์— ๋”์ด์ƒ ์˜์กดํ•˜์ง€ ์•Š๊ฒŒ ๋œ ๋‹ค์Œ ๋ฒˆ์˜ ์ฃผ์š” ์—…๋ฐ์ดํŠธ์—์„œ๋Š” ์ œ๊ฑฐํ•  ์˜ˆ์ •์ด๋ผ๊ณ  ํ•˜๋‹ˆ ๋˜๋„๋ก ์‚ฌ์šฉ์„ ์ง€์–‘ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๊ฒ ๋‹ค.

๐Ÿ”Ž References

profile
An investment in knowledge pays the best interest๐Ÿ™ƒ

0๊ฐœ์˜ ๋Œ“๊ธ€