πŸ€” useState μ΅œμ‹ ν™”κ°€ μ•ˆλœλ‹€? (Closure, Scope)

이도경·2024λ…„ 2μ›” 24일
0

fRONTeND

λͺ©λ‘ 보기
14/14
post-thumbnail

React κ°œλ°œμ„ ν•˜λ‹€λ³΄λ©΄ useState κΈ°λŠ₯을 μ•„μ£Ό 많이 μ‚¬μš©ν•˜λŠ”λ°μš”, 예λ₯Ό λ“€μ–΄μ„œ κ°„λ‹¨ν•œ μΉ΄μš΄ν„° μ»΄ν¬λ„ŒνŠΈλ₯Ό λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€.

μ˜ˆμ‹œ

const Counter = () => {
	const [count, setCount] = useState(0);
  
  	const incrementNumber = () => {
		setCount(count + 1);
		console.log(count);
	};

	return (
		<button onClick={incrementNumber}>
			{count}
		</button>
  	);
}

μΉ΄μš΄ν„°λ₯Ό 찍어보면...

? πŸ€”

그런데 μ΄μƒν•˜μ£ ? μ½˜μ†”κ³Ό λ””μŠ€ν”Œλ ˆμ΄κ°€ μ°¨μ΄λ‚˜λŠ” 상황이 λ°œμƒν•©λ‹ˆλ‹€.
이 문제λ₯Ό Closure와 Scope 라고 ν•©λ‹ˆλ‹€.

ClosureλŠ” ν•¨μˆ˜κ°€ μ„ μ–Έλœ λ ‰μ‹œμ»¬ ν™˜κ²½μ„ κΈ°μ–΅ν•˜μ—¬ ν•¨μˆ˜κ°€ λ ‰μ‹œμ»¬ ν™˜κ²½ λ°–μ—μ„œ 싀행될 λ•Œμ—λ„ 이 ν™˜κ²½μ— μ ‘κ·Όν•  수 있게 ν•˜λŠ” κΈ°λŠ₯μž…λ‹ˆλ‹€. 즉, ν•¨μˆ˜λŠ” μžμ‹ μ΄ μ„ μ–Έλœ λ²”μœ„ λ°–μ˜ λ³€μˆ˜λ₯Ό μ°Έμ‘°ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

  • ν•¨μˆ˜κ°€ 싀행될 λ•Œ, λ ‰μ‹œμ»¬ ν™˜κ²½μ€ μŠ€νƒμ— μ €μž₯λ©λ‹ˆλ‹€.
  • ν•¨μˆ˜κ°€ λ ‰μ‹œμ»¬ ν™˜κ²½ λ°–μ—μ„œ 싀행될 λ•Œμ—λ„ μŠ€νƒμ— μ €μž₯된 λ ‰μ‹œμ»¬ ν™˜κ²½μ— μ ‘κ·Όν•  수 μžˆμŠ΅λ‹ˆλ‹€.

ScopeλŠ” ν”„λ‘œκ·Έλž¨μ—μ„œ λ³€μˆ˜, ν•¨μˆ˜, μƒμˆ˜ λ“±μ˜ μ‹λ³„μžκ°€ μœ νš¨ν•œ λ²”μœ„λ₯Ό μ˜λ―Έν•©λ‹ˆλ‹€. 즉, μ–΄λ””μ—μ„œ μ–΄λ–€ μ‹λ³„μžλ₯Ό μ‚¬μš©ν•  수 μžˆλŠ”μ§€λ₯Ό κ²°μ •ν•©λ‹ˆλ‹€.

원인

μœ„μ˜ μƒν™©μ˜ μ˜ˆμ‹œλ‘œ λ“€μžλ©΄

  • λ Œλ” 츑은 μ΅œμ‹  count 값을 λ°˜μ˜ν•˜μ§€λ§Œ incrementNumber() ν•¨μˆ˜λŠ” 초기 값을 μ‚¬μš©ν•©λ‹ˆλ‹€.
  • 비동기 처리둜 인해 incrementNumber() ν•¨μˆ˜ λ‚΄μ—μ„œ count κ°’ μ—…λ°μ΄νŠΈκ°€ λ Œλ”λ§ 이후에 λ°œμƒν•©λ‹ˆλ‹€.
const incrementNumber = () => {
	setCount(count + 1); // 0 -> 1 증가
	console.log(count); // 0 좜λ ₯
};

ν•΄κ²°?

이런 상황을 ν•΄κ²°ν•˜κΈ° μœ„ν•΄μ„œλŠ” λ‹€μ–‘ν•œ 방법이 μžˆλŠ”λ°μš”. κ·Έ 쀑 λͺ‡ 가지λ₯Ό μ œμ•ˆν•©λ‹ˆλ‹€.

  1. setState 이전값 μ°Έμ‘°ν•˜κΈ°
setCount((prev) => {
	const newCount = prev + 1;
	console.log(newCount);
	return newCount;
});

setState μ½œλ°±ν•¨μˆ˜ λ‚΄μ˜ arg둜 이전 값을 λ°˜ν™˜ν•˜κΈ° λ•Œλ¬Έμ—, μ›ν•˜λŠ” κΈ°λŠ₯을 넣어버리면 해결될 것 μž…λ‹ˆλ‹€. μ œκ°€ 자주 μ‚¬μš©ν•˜λŠ” 방법이기도 ν•˜κ΅¬μš”.

  1. useEffectμ—μ„œ κ°μ§€ν•˜κΈ°
  useEffect(() => {
    if (count === 10) console.log('10 μž…λ‹ˆλ‹€.');
  }, [count]);

λ˜λŠ” useEffectλ₯Ό ν™œμš©ν•˜μ—¬ dependency array에 감지할 λ³€μˆ˜λ₯Ό λ„£μŠ΅λ‹ˆλ‹€.

  1. let, useRef μ‚¬μš©ν•˜κΈ°
let count2 =0;
const countRef = useRef(0);

return (
    <>
      <button
        onClick={() => {
          count2 += 1;
          console.log(`let ${count2}`);
        }}
      >
        let {count2}
      </button>
      <button
        onClick={() => {
          countRef.current += 1;
          console.log(`ref ${countRef.current}`);
        }}
      >
        useRef {countRef.current}
      </button>
    </>
  );

μ£Όμ˜ν•  점은 letκ³Ό useRefλŠ” κ°’ 변화에 따라 λ Œλ”λ§ νŠΈλ¦¬κ±°ν•˜μ§€ μ•Šμ•„ ν™”λ©΄μ—λŠ” 0만 보이게 될 것 μž…λ‹ˆλ‹€.

λ””μŠ€ν”Œλ ˆμ΄ μš©μœΌλ‘œλŠ” μ ν•©ν•˜μ§€ μ•Šκ΅°μš”. ν•˜μ§€λ§Œ ν•¨μˆ˜ λ‚΄ μƒνƒœ κ°μ§€λ‘œλŠ” μ μ ˆν•  지 λͺ¨λ₯΄κ² μŠ΅λ‹ˆλ‹€.

κ²°λ‘ 

정닡은 μ—†λŠ”κ²ƒ κ°™μŠ΅λ‹ˆλ‹€. μ΅œμ ν™” 등을 κ³ λ €ν•˜μ—¬ μ μ ˆν•œ 곳에 μ‚¬μš©ν•˜λ©΄ μ’‹κ² λ„€μš”.

profile
μ•ˆλ…•ν•˜μ„Έμš©

0개의 λŒ“κΈ€