React๋ก ํผ์ ๋ง๋ค๊ณ , ์
๋ ฅ์ฐฝ์์ Enter ํค๋ฅผ ๋๋ฅด๋ฉด ๋ค์ ํ๋๋ก ํฌ์ปค์ค๋ฅผ ์ด๋์ํค๋ ๊ธฐ๋ฅ์ ๊ตฌํํ๋ค.
๊ทธ๋ฐ๋ฐ ํ๊ธ ์
๋ ฅ ์ ๋ง์ง๋ง ๊ธ์๊ฐ ๋ค์ ์ธํ ํ๋๋ก ์ด๋ํ๋ ๋ฒ๊ทธ๊ฐ ๋ฐ์ํ๋ค.
์์ด, ์ซ์, ํน์๋ฌธ์๋ ๋ฌธ์ ๊ฐ ์๊ณ , ํ๊ธ์์๋ง ๋ํ๋ฌ๋ค.
์์ธ: IME ์กฐํฉ ์ํ์ onKeyDown ์ด๋ฒคํธ ํ์ด๋ฐ์ ์ถฉ๋
์ด ๋ฌธ์ ๋ IME(Input Method Editor, ์ ๋ ฅ๊ธฐ) ์กฐํฉ ๋ฐฉ์๊ณผ ์ด๋ฒคํธ ๋ฐ์ ์์๊ฐ ์ถฉ๋ํ๊ธฐ ๋๋ฌธ์ ๋ฐ์ํ๋ค.
IME์ ์ ๋ ฅ ๋ฐฉ์
ํ๊ธ์ ์กฐํฉํ ์
๋ ฅ ์ธ์ด๋ค. ์๋ฅผ ๋ค์ด ‘์ฌ’๋ผ๋ ๊ธ์๋ฅผ ์
๋ ฅํ ๋ ์ค์ ๋ก๋ ๋ค์๊ณผ ๊ฐ์ ๊ณผ์ ์ ๊ฑฐ์น๋ค.
• ์ฌ์ฉ์๊ฐ ‘ใ
’ ์
๋ ฅ
• ‘ใ
’ ์
๋ ฅ → ์กฐํฉ → ‘์ฌ’ ์์ฑ
์ด๋ ์กฐํฉ์ด ๋๋์ง ์์ ์ํ๋ ๋ธ๋ผ์ฐ์ ์์๋ isComposing = true ๋ก ํ๋จ๋๋ค.
๋ฌธ์ ๋ฐ์ ํ๋ฆ
1. ์ฌ์ฉ์๊ฐ ‘์ฌ’๋ฅผ ์ ๋ ฅ ์ค์ด๋ค.
2. ์ด๋ ‘ใ ’ + ‘ใ ’๋ ์์ง ์กฐํฉ ์ค ์ํ๋ค.
3. ์ฌ์ฉ์๊ฐ Enter ํค๋ฅผ ๋๋ฅธ๋ค.
4. React์ onKeyDown ์ด๋ฒคํธ๊ฐ ์กฐํฉ์ด ํ์ ๋๊ธฐ ์ ์ ์คํ๋๋ค.
5. e.preventDefault()์ ์ํด ํฌ์ปค์ค๊ฐ ๋ค์ ์ธํ์ผ๋ก ๊ฐ์ ๋ก ์ด๋๋๋ค.
6. ์กฐํฉ ์ค์ด๋ ๊ธ์ ‘ใ ’๊ฐ ๋ค์ ์ธํ์ ๋ถ๊ฒ ๋๋ค.
์ด๋ฌํ ํ๋ฆ์ผ๋ก ์ธํด ์กฐํฉ์ด ๋๋๊ธฐ ์ ์ ํฌ์ปค์ค๋ฅผ ์ฎ๊ธฐ๋ฉด์ ๋ฌธ์ ๋ถ๋ฆฌ ํ์์ด ๋ฐ์ํ๊ฒ ๋๋ค.
์กฐํฉํ ์ ๋ ฅ ์ธ์ด (Composition-based language): ์ฌ๋ฌ ํค ์ ๋ ฅ์ ์กฐํฉํ์ฌ ํ ๊ธ์๋ฅผ ์์ฑํ๋ ์ธ์ด
ex. ํ๊ธ, ํ๋ผ๊ฐํ/๊ฐํ์นด๋/ํ์
ํด๊ฒฐ ๋ฐฉ๋ฒ: isComposing ์ํ๋ฅผ ์ฒดํฌํ์ฌ Enter ์ด๋ฒคํธ ์ฒ๋ฆฌ
๋ธ๋ผ์ฐ์ ์ KeyboardEvent ๊ฐ์ฒด์๋ isComposing์ด๋ผ๋ ์์ฑ์ด ์๋ค. ์ด๋ฅผ ํตํด ํ์ฌ ์ ๋ ฅ์ด ์กฐํฉ ์ค์ธ์ง ํ๋จํ ์ ์๋ค.
React์์๋ ์ด๋ฒคํธ ๊ฐ์ฒด๊ฐ ํฉ์ฑ ์ด๋ฒคํธ(SyntheticEvent)์ด๊ธฐ ๋๋ฌธ์ ์ง์ isComposing ์์ฑ์ ์ฌ์ฉํ ์ ์๋ค.
๋์ e.nativeEvent.isComposing์ ์ฌ์ฉํ์ฌ ํ๋จํด์ผ ํ๋ค.
์ด ์ฝ๋๋ IME ์กฐํฉ ์ํ๊ฐ ์๋ ๊ฒฝ์ฐ์๋ง Enter ํค๋ฅผ ์ฒ๋ฆฌํ์ฌ ๋ค์ ์ธํ์ผ๋ก ํฌ์ปค์ค๋ฅผ ์ด๋์ํจ๋ค.
export const handleEnterAsTab = (e: React.KeyboardEvent) => {
if (e.key === "Enter" && !e.nativeEvent.isComposing) {
e.preventDefault();
const form = e.currentTarget as HTMLElement;
const focusable = Array.from(
form.querySelectorAll<HTMLElement>(
'input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'
)
).filter((el) => !el.classList.contains("ant-picker-input"));
const index = focusable.indexOf(document.activeElement as HTMLElement);
if (index > -1 && index < focusable.length - 1) {
focusable[index + 1].focus();
}
}
};
React์ ํฉ์ฑ ์ด๋ฒคํธ(Synthetic Event)์์ ๊ด๊ณ
ํฉ์ฑ ์ด๋ฒคํธ๋
React๋ ๋ธ๋ผ์ฐ์ ์ด๋ฒคํธ๋ฅผ ์ง์ ์ฌ์ฉํ๋ ๊ฒ์ด ์๋๋ผ, SyntheticEvent๋ผ๋ ํฉ์ฑ ์ด๋ฒคํธ ๊ฐ์ฒด๋ก ๊ฐ์ธ์ ์ ๊ณตํ๋ค.
<input onClick={(e) => console.log(e)} />
์ ์์์์ e๋ ๋ธ๋ผ์ฐ์ ์ MouseEvent๊ฐ ์๋๋ผ React๊ฐ ๋ํํ SyntheticEvent์ด๋ค.
์ ํฉ์ฑ ์ด๋ฒคํธ๋ฅผ ์ฌ์ฉํ๋๊ฐ
1. ๋ธ๋ผ์ฐ์ ๊ฐ ํธํ์ฑ
- ์ด๋ฒคํธ ๋์์ด ๋ธ๋ผ์ฐ์ ๋ง๋ค ๋ค๋ฅด๋ฏ๋ก ์ผ๊ด๋ ์ฒ๋ฆฌ๋ฅผ ์ํด.
2. ์ฑ๋ฅ ์ต์ ํ
- ๊ณผ๊ฑฐ React 16 ์ดํ์์๋ ์ด๋ฒคํธ ํ๋ง ๊ธฐ๋ฒ์ ์ฌ์ฉํ์ฌ ์ด๋ฒคํธ ๊ฐ์ฒด๋ฅผ ์ฌ์ฌ์ฉํ๋ค. ์ด๋ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ์ ์ค์ด๊ณ GC(Garbage Collection) ๋ถํ๋ฅผ ์ค์ด๊ธฐ ์ํ ๋ชฉ์ ์ด์๋ค.
- ํ์ง๋ง React 17๋ถํฐ๋ ์ด๋ฒคํธ ํ๋ง์ด ์ค๋จ๋์๋ค. ์ด์ ์ด๋ฒคํธ ๊ฐ์ฒด๋ ํญ์ ์๋ก ์์ฑ๋๋ค.
- ๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ SyntheticEvent๋ ์ด๋ฒคํธ ์์๊ณผ ํจ๊ป ๋์ํ๋ฉด์ ๋ถํ์ํ ๋ฆฌ์ค๋ ๋ฑ๋ก์ ์ค์ฌ ์ฑ๋ฅ ์ต์ ํ์ ๊ธฐ์ฌํ๋ค.
3. ์ด๋ฒคํธ ์์ (Event Delegation) : ์ด๋ฒคํธ๋ฅผ ๋ฃจํธ์์ ํ๋ฒ์ ์ฒ๋ฆฌํ์ฌ ๋ ๋๋ง ์ฑ๋ฅ์ ๊ฐ์
- ๋ฆฌ์กํธ๋ ๋ฃจํธ DOM ๋ ธ๋์ ํ๋์ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ง ๋ฑ๋กํ ๋ค, ๋ด๋ถ์ ์ผ๋ก ์ด๋ฒคํธ๋ฅผ ์บก์ณํด์ ํ์ํ ์ปดํฌ๋ํธ์ ์ ๋ฌํ๋ค.
- ์ด์ ๋ฐ๋ผ ์์ฒ ๊ฐ์ DOM ์์ ๊ฐ๊ฐ์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ถ์ด์ง ์์๋ ๋๋ค.
๊ฒฐ๊ณผ์ ์ผ๋ก ๋ ๋๋ง ์ฑ๋ฅ๊ณผ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ ํจ์จ์ด ํฌ๊ฒ ํฅ์๋๋ค.
nativeEvent์ ์ญํ
SyntheticEvent ๋ด๋ถ์๋ ์ค์ ๋ธ๋ผ์ฐ์ ์ด๋ฒคํธ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๋ nativeEvent ์์ฑ์ด ์๋ค.
isComposing์ฒ๋ผ ๋ธ๋ผ์ฐ์ ์์๋ง ์กด์ฌํ๋ ์์ฑ์ ์ด nativeEvent๋ฅผ ํตํด ์ ๊ทผํด์ผ ํ๋ค.
<input
onKeyDown={(e) => {
console.log('SyntheticEvent:', e);
console.log('NativeEvent:', e.nativeEvent);
}}
/>
ref
• MDN - KeyboardEvent.isComposing