λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
πŸ—‚ WIL/πŸ“ React

πŸ› λ¦¬λ Œλ”λ§ 이슈 ν•΄κ²°ν•˜κΈ°

by nalong 2025. 3. 23.

에디터 μœ„μ— μƒˆλ‘œμš΄ κΈ°λŠ₯을 μΆ”κ°€ν•˜λŠ” 에픽을 μ‹œμž‘ν•˜κ²Œ λ˜λ©΄μ„œ λ“œλž˜κ·Έ, ν…μŠ€νŠΈ μž…λ ₯, μŠ€ν…νΌλ‘œ attr 값을 μ—…λ°μ΄νŠΈν•  수 μžˆλŠ” κΈ°λŠ₯을 κ°œλ°œν•˜κ²Œ λ˜μ—ˆλ‹€. κΈ°λŠ₯ νŠΉμ„±μƒ μƒνƒœ λ³€ν™”κ°€ 자주 λ°œμƒν•˜κΈ° λ•Œλ¬Έμ—, React DevTools의 Highlight updates μ˜΅μ…˜μ„ ν™œμ„±ν™”ν•œ μƒνƒœλ‘œ κ΄€μ°°ν•˜λ©° κ°œλ°œμ„ μ§„ν–‰ν–ˆλŠ”λ°, μŠ€ν¬λ‘€μ΄λ‚˜ νŠΉμ • μƒνƒœ 변경이 λ°œμƒν•  λ•Œλ§ˆλ‹€ λͺ¨λ“  μ•‘ν‹°λΉ„ν‹° 블둝이 λ™μ‹œμ— λ¦¬λ Œλ”λ§ λ˜λŠ” ν˜„μƒμ„ λ°œκ²¬ν–ˆλ‹€.
( μ—λ””ν„°λŠ” 각 μ•‘ν‹°λΉ„ν‹°λ§ˆλ‹€ ν•˜λ‚˜μ”© λ Œλ”λ§ 되며, 전체 μ•‘ν‹°λΉ„ν‹°κ°€ 리슀트 ν˜•νƒœλ‘œ κ΅¬μ„±λ˜μ–΄ μžˆλ‹€. κΈ°λŠ₯μ μœΌλ‘œλŠ” νŠΉμ • μ•‘ν‹°λΉ„ν‹° ν•˜λ‚˜λ§Œ μˆ˜μ •λ˜λŠ” μƒν™©μ΄μ—ˆμŒμ—λ„ λ¦¬μŠ€νŠΈμ— ν¬ν•¨λœ λͺ¨λ“  에디터가 ν•¨κ»˜ λ¦¬λ Œλ”λ§ 되고 μžˆμ—ˆλ‹€.)
μ²˜μŒμ—λŠ” λ‚΄κ°€ μΆ”κ°€ν•œ κΈ°λŠ₯μ—μ„œ λ°œμƒν•œ 문제라고 μƒκ°ν–ˆμ§€λ§Œ, κ΄€λ ¨λœ λ‘œμ§μ„ ν•˜λ‚˜μ”© μ œκ±°ν•΄λ³΄λ©° ν™•μΈν•œ κ²°κ³Ό, ν•΄λ‹Ή μ΄μŠˆλŠ” 이미 κΈ°μ‘΄λΆ€ν„° μ‘΄μž¬ν•˜λ˜ λ¬Έμ œμ˜€λ‹€. μ΄ˆκΈ°ν™” μ‹œμ μ— μ‹€ν–‰λ˜λŠ” μƒνƒœ λ¨Έμ‹  둜직이 전체 λ¦¬λ Œλ”λ§μ„ μœ λ°œν•˜κ³  μžˆμ—ˆκ³ , 이 뢀뢄을 ν•΄κ²°ν•˜κΈ° μœ„ν•΄ λ‚΄λΆ€ ꡬ쑰λ₯Ό μ‚΄νŽ΄λ³΄κΈ° μ‹œμž‘ν–ˆλ‹€.

πŸš‘ useMachine → useInterpret μ „ν™˜

useEffect(() => {
  service.send({
    type: 'INIT',
    payload: {
      items,
      focusItemId,
    },
  });
}, [items, focusItemId]);

 
ν•΄λ‹Ή INIT μ•‘μ…˜μ€ contextλ₯Ό μž¬μ„€μ •ν•˜λŠ” λ™μž‘μ„ ν¬ν•¨ν•˜κ³  μžˆμ—ˆκ³ , 이 context의 λ³€ν™”κ°€ ꡬ독 쀑인 λͺ¨λ“  블둝에 영ν–₯을 μ£Όλ©΄μ„œ 전체 λ¦¬λ Œλ”λ§μ΄ λ°œμƒν–ˆλ‹€.

νŒ€μ›μ—κ²Œ 이 문제λ₯Ό κ³΅μœ ν•˜λ˜ 쀑, useInterpretλ₯Ό ν™œμš©ν•˜λ©΄ λ¦¬λ Œλ”λ§ μ œμ–΄μ— μœ λ¦¬ν•˜λ‹€λŠ” 쑰언을 λ“€μ—ˆκ³ , ν•΄λ‹Ή λ°©ν–₯으둜 λ‹€λ₯Έ νŒ€μ›λΆ„κ³Ό ν•¨κ»˜ λ¦¬νŒ©ν„°λ§μ„ μ§„ν–‰ν•˜κ²Œ λ˜μ—ˆλ‹€. 곡식 λ¬Έμ„œμ—μ„œλ„ 두 ν›…μ˜ 차이λ₯Ό μ•„λž˜μ™€ 같이 μ„€λͺ…ν•˜κ³  μžˆλ‹€. 

useMachine automatically subscribes to the current state of the machine, which means every state update will result in a re-render of the component that calls it. This re-rendering isn’t always desirable.

useInterpret allows you to interpret a machine without subscribing to its updates, which means that by default, it won’t cause any re-rendering in the component.

 
이후 useInterpretλ₯Ό μ‚¬μš©ν•΄ μƒνƒœ 머신을 κ΅¬λ™ν•˜κ³ , μƒνƒœ ꡬ독이 ν•„μš”ν•œ μœ„μΉ˜μ—μ„œλ§Œ useSelectorλ₯Ό 톡해 λͺ…μ‹œμ μœΌλ‘œ κ΅¬λ…ν•˜λ„λ‘ ꡬ쑰λ₯Ό λ³€κ²½ν–ˆλ‹€.

⭐️ 참고둜, XState v5 κΈ°μ€€μœΌλ‘œλŠ” useInterpret 훅이 useActorRef둜 λ³€κ²½λ˜μ—ˆλ‹€. μš°λ¦¬λŠ” ν˜„μž¬ v4 기반으둜 개발 쀑이기 λ•Œλ¬Έμ— μ—¬μ „νžˆ useInterpretλ₯Ό μ‚¬μš©ν•˜κ³  μžˆλ‹€. 

πŸš‘  useSelector 쑰건 λΆ„κΈ°

μœ„μ˜ 문제λ₯Ό ν•΄κ²°ν–ˆμŒμ—λ„ λΆˆκ΅¬ν•˜κ³  계속 λ¦¬λ Œλ”λ§ μ΄μŠˆλŠ” λ‚¨μ•„μžˆμ—ˆκ³ , λ‹€μ‹œ 디버깅을 ν•œ κ²°κ³Ό μ•„λž˜μ™€ λΉ„μŠ·ν•œ μ½”λ“œλ‘œ 인해 λ¦¬λ Œλ”λ§μ΄ μΌμ–΄λ‚˜κ³  μžˆμ—ˆλ‹€. 

const data = useSelector(service, (state) => state.context.sharedData);

 
sharedDataκ°€ 변경될 λ•Œλ§ˆλ‹€ 이λ₯Ό κ΅¬λ…ν•˜κ³  μžˆλŠ” λͺ¨λ“  μ»΄ν¬λ„ŒνŠΈκ°€ λ¦¬λ Œλ”λ§ λ˜λŠ” κ΅¬μ‘°μ˜€λ‹€. sharedDataλŠ” 전체 context μ•ˆμ— μ‘΄μž¬ν•˜λŠ” 값이기 λ•Œλ¬Έμ—, 일뢀 ν•­λͺ©λ§Œ λ³€κ²½λ˜μ–΄λ„ 전체가 λ°˜μ‘ν•˜κ³  μžˆμ—ˆλ‹€. ν•΄λ‹Ή 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄, ν˜„μž¬ μ„ νƒλœ ν•­λͺ©μ— ν•΄λ‹Ήν•  λ•Œλ§Œ κ΅¬λ…ν•˜λ„λ‘ 쑰건을 μΆ”κ°€ν–ˆλ‹€.

const data = useSelector(service, (state) => {
  if (localId !== state.context.selectedId) return undefined;
  return state.context.sharedData;
});

 
μœ„μ™€ 같이 μ²˜λ¦¬ν•¨μœΌλ‘œμ¨, μƒνƒœ 변경이 λ°œμƒν•˜λ”λΌλ„ ν˜„μž¬ ν•­λͺ©μ— ν•΄λ‹Ήν•˜λŠ” λΈ”λ‘λ§Œ λ¦¬λ Œλ”λ§ 되고, κ·Έ μ™Έμ˜ 블둝은 영ν–₯을 λ°›μ§€ μ•Šκ²Œ λ˜μ—ˆκ³ , ν•˜λ‚˜μ˜ 변경사항이 μžˆμ„ λ•Œ λͺ¨λ“  μ•‘ν‹°λΉ„ν‹°κ°€ λ¦¬λ Œλ”λ§ λ˜λŠ” μ΄μŠˆλŠ” 두 κ°€μ§€ λ°©μ‹μœΌλ‘œ λ§ˆλ¬΄λ¦¬λ˜μ—ˆλ‹€.  
 
κΈ°λŠ₯ ν•˜λ‚˜ κ°œλ°œν•˜λ‹€κ°€ μš°μ—°νžˆ 자주 μ“°μ΄λŠ” μ˜μ—­μ˜ λ¦¬λ Œλ”λ§ λ¬Έμ œκΉŒμ§€ ν•¨κ»˜ ν•΄κ²°ν•˜κ²Œ λ˜μ–΄, κ°œμΈμ μœΌλ‘œλ„ κ½€ λΏŒλ“―ν•˜μ˜€λ‹€. πŸ™‚