ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

## ๋ฌธ์ œ์ 

๊ฐœ์ธ ํ”„๋กœ์ ํŠธ (์ค„์—ฌ์„œ ๋งˆํˆฌ์‚ฌ)๋ฅผ ์ง„ํ–‰ํ•˜๋Š”๋ฐ ํˆฌ๋‘๋ฅผ ๋“ฑ๋กํ•˜๋Š” ๊ณผ์ •์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.

๋ถ„๋ช… ํ•˜๋‚˜์˜ ํˆฌ๋‘๋งŒ ์ž…๋ ฅํ–ˆ๋Š”๋ฐ ๋งจ ๋’ท ๊ธ€์ž๊ฐ€ ์ถ”๊ฐ€๋กœ ๋“ฑ๋ก๋˜๋Š” ๋ฌธ์ œ์˜€๋‹ค.
onKeyDown ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒ๋  ๋•Œ ๋ฐ์ดํ„ฐ๊ฐ€ ์ถ”๊ฐ€๋˜๋„๋ก ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ ๋ถ€๋ถ„์„ ๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค.


// ๋“ฑ๋ก ๋ฒ„ํŠผ ํด๋ฆญ
  const onClickAddTodo = (e) => {
    if (inputValue && e.key === "Enter") {
      setTodoData((prev) => [
        ...prev,
        {
          id: Date.now(),
          content: inputValue,
          isEdit: false,
          isDone: false,
        },
      ]);
      setInputValue("");
    }
  };

<Input
  placeholder="ํ• ์ผ ๋“ฑ๋ก"
  value={inputValue}
  onChange={onChangeInput}
  onKeyDown={(e) => onClickAddTodo(e)}
/>

์•„๋ฌด๋ฆฌ๋ด๋„ ๋“ฑ๋ก ํ•จ์ˆ˜๋ถ€๋ถ„์—์„œ๋Š” ์ด์ƒํ•œ ์ ์ด ์—†๋Š” ๊ฒƒ ๊ฐ™์•˜๋‹ค.

์„ค๋งˆ onKeyDown์ด ๋ฌธ์ œ์ผ๊นŒ? ์‹ถ์–ด์„œ ์ข€ ์ฐพ์•„๋ดค๋”๋‹ˆ onKeyDown ์ด๋ฒคํŠธ์˜ ๋™์ž‘๋ฐฉ์‹๊ณผ ํ•œ๊ธ€ ์ž…๋ ฅ๋ฐฉ์‹์ด ๊ด€๋ จ์ด ์žˆ์—ˆ๋‹ค.

onKeyDown

onKeyDown์€ ํ‚ค๋ฅผ ๋ˆŒ๋ €์„ ๋•Œ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ํ‚ค๋ณด๋“œ ์ด๋ฒคํŠธ ํ•จ์ˆ˜์ด๋‹ค.
'ํฌ๋„'๋ฅผ ์ž…๋ ฅํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์•˜์„ ๋•Œ,

'ใ…' ํ‚ค ์ž…๋ ฅ -> ์ด๋ฒคํŠธ ๋ฐœ์ƒ -> ๋ˆ„๋ฅผ ๋‹น์‹œ input์˜ value ๊ฐ’์€ ๊ณต๋ฐฑ์ด๋ฏ€๋กœ ''
'ใ…—' ํ‚ค ์ž…๋ ฅ -> ์ด๋ฒคํŠธ ๋ฐœ์ƒ -> ใ…
'ใ„ท' ํ‚ค ์ž…๋ ฅ -> ์ด๋ฒคํŠธ ๋ฐœ์ƒ -> ํฌ
'ใ…—' ํ‚ค ์ž…๋ ฅ -> ์ด๋ฒคํŠธ ๋ฐœ์ƒ -> ํณ
'enter' ํ‚ค ์ž…๋ ฅ -> ์ด๋ฒคํŠธ ๋ฐœ์ƒ -> 'ํฌ๋„' ๋ฐ์ดํ„ฐ๊ฐ€ ์ €์žฅ

์ด๋Ÿฐ ์ˆœ์„œ๋กœ ์ง„ํ–‰์ด ๋œ๋‹ค.

๊ทธ๋Ÿผ '๋„'๋Š” ๋„๋Œ€์ฒด ์–ด๋””์„œ ์ƒ๊ฒจ๋‚˜์„œ ์ €์žฅ์ด ๋˜๋Š”๊ฑธ๊นŒ?

์˜ˆ์‹œ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค์–ด์„œ ํ…Œ์ŠคํŠธํ•ด๋ณด์ž!

ํฌ๋„๋ฅผ ํ•œ๊ธ€๊ณผ ์˜์–ด๋กœ ๊ฐ๊ฐ ์ž…๋ ฅํ•œ ํ›„ ์—”ํ„ฐ๋ฅผ ๋ˆŒ๋Ÿฌ๋ณด์•˜๋‹ค.

'ํฌ๋„'๋ฅผ ์ž…๋ ฅํ–ˆ์„ ๊ฒฝ์šฐ, ์—”ํ„ฐ๋ฅผ ๋ˆŒ๋ €์„ ๋•Œ ์ž…๋ ฅ๊ธฐ ์ƒ์œผ๋กœ ์•„์ง ์™„์„ฑ๋œ ๋‹จ์–ด๋กœ ์ธ์‹์ด ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์—”ํ„ฐ๋ฅผ ๋ˆŒ๋ €๋‹ค๊ฐ€ ๋—„ ๊ฒฝ์šฐ์—๋„ ์ถ”๊ฐ€๋กœ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค.

ํ•˜์ง€๋งŒ 'grape'๋ฅผ ์ž…๋ ฅํ–ˆ์„ ๊ฒฝ์šฐ, ์˜์–ด ํŠน์„ฑ ์ƒ ํ•œ ๊ธ€์ž๊ฐ€ ๋‹จ์ผ ํ‚ค ์ž…๋ ฅ์œผ๋กœ ์™„์„ฑ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์—”ํ„ฐ๋ฅผ ๋ˆŒ๋ €์„ ๋•Œ ๋‹จ์–ด๋Š” ์ด๋ฏธ ์™„์„ฑ๋œ ์ƒํƒœ๋กœ ์ธ์‹๋œ๋‹ค.

์ด ํ˜„์ƒ์€ isComposing์ด๋ผ๋Š” ์†์„ฑ๊ณผ๋„ ์—ฐ๊ด€์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ๋„ ํ•จ๊ป˜ ์•Œ์•„๋ณด์ž.

isComposing

isComposing์€ ํ˜„์žฌ ๊ฐ’์ด ์ž…๋ ฅ์ด ์™„๋ฃŒ๋œ ์ƒํƒœ์ธ์ง€ ์•„๋‹Œ์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด์ฃผ๋Š” ์†์„ฑ์ด๋‹ค.
(isComposing์ด true์ด๋ฉด ์ž…๋ ฅ ์ค‘์ด๋ผ๋Š” ์˜๋ฏธ, false์ด๋ฉด ์ž…๋ ฅ์ด ์™„๋ฃŒ๋˜์—ˆ๋‹ค๋Š” ์˜๋ฏธ!)

์œ„์˜ ์˜ˆ์‹œ์— ๋Œ€์ž…ํ•ด๋ณด๋ฉด ํ•œ๊ธ€๋กœ 'ํฌ๋„'๋ฅผ ์ž…๋ ฅํ–ˆ์„ ๊ฒฝ์šฐ, ์—”ํ„ฐ๋ฅผ ๋ˆ„๋ฅธ ์ˆœ๊ฐ„์— isComposing์ด true์ธ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์ด๋Š” ์œ„์—์„œ๋„ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์•„์ง ์™„์„ฑ๋œ ๋‹จ์–ด๋กœ ์ธ์‹์ด ๋˜์ง€ ์•Š์•˜๋‹จ ๋œป์ด๋‹ค.
๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์—”ํ„ฐ๋ฅผ ๋ˆŒ๋ €๋‹ค๊ฐ€ ๋–ผ๋Š” ์ˆœ๊ฐ„์—๋„ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ฒŒ ๋œ๋‹ค.

๊ทธ์— ๋ฐ˜ํ•ด 'grape'๋ฅผ ์ž…๋ ฅํ–ˆ์„ ๊ฒฝ์šฐ, ์—”ํ„ฐ๋ฅผ ๋ˆ„๋ฅธ ์ˆœ๊ฐ„์— isComposing์ด false์ธ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์ด๋Š” ์—ญ์‹œ ์œ„์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์™„์„ฑ๋œ ๋‹จ์–ด๋กœ ์ธ์‹ํ–ˆ๋‹ค๋Š” ๋œป์ด๋‹ค.
๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์ถ”๊ฐ€๋กœ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค์ง€ ์•Š๋Š”๋‹ค.

์ถ”๊ฐ€๋กœ ์ด ์†์„ฑ์€ ์šด์˜์ฒด์ œ๋‚˜ ๋ธŒ๋ผ์šฐ์ €์— ๋”ฐ๋ผ ์ง€์›ํ•˜๊ณ  ํ•ด์„ํ•˜๋Š” ๋ฐฉ์‹์ด ๋‹ฌ๋ผ์„œ ๊ฒฐ๊ณผ๊ฐ’์ด ๋‹ค๋ฅด๊ฒŒ ๋‚˜์˜ค๊ธฐ๋„ ํ•œ๋‹ค.

์œ„ ์‚ฌ์ง„๊ณผ ๊ฐ™์ด window ์šด์˜์ฒด์ œ์—์„œ๋Š” ํ•œ๊ธ€ ์ž…๋ ฅ ์‹œ์—๋„ 'isComposing' ๊ฐ’์ด false๋กœ ์„ค์ •๋˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ๊ณ 

๋งฅ๋ถ์—์„œ๋Š” ํ•œ๊ธ€ ์ž…๋ ฅ ์‹œ isComposing ๊ฐ’์ด true๋กœ ์„ค์ •๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.

๊ทธ๋ž˜์„œ ๋„๋Œ€์ฒด '๋„'๋Š” ์™œ ๋‚˜์˜ค๋Š”๊ฑธ๊นŒ?๐Ÿค”

ํ•œ๊ธ€๋กœ ์ž‘์„ฑํ•  ๊ฒฝ์šฐ์—๋Š” '์ดˆ์„ฑ -> ์ค‘์„ฑ -> ์ข…์„ฑ' ์˜ ์กฐํ•ฉ์œผ๋กœ ํ•œ๊ธ€ ๊ธ€์ž ํ•˜๋‚˜๋ฅผ ์™„์„ฑ์‹œํ‚ค๊ฒŒ ๋˜๋Š”๋ฐ
์šฐ๋ฆฌ๋Š” 'ํฌ๋„'๋ฅผ ์ž…๋ ฅํ–ˆ๊ณ  ๊ทธ๊ฒŒ ์ด๋ฏธ ์™„์„ฑ๋œ ๊ธ€์ž๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ,
์ž…๋ ฅ๊ธฐ ์ž…์žฅ์—์„œ๋Š” ใ…(์ดˆ์„ฑ) + ใ…—(์ค‘์„ฑ) + ใ„ท(์ข…์„ฑ) + ใ…—(??) ์œผ๋กœ ์ƒ๊ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์—
ํฌ๋„๋ผ๋Š” ๊ธ€์ž๋Š” ์™„์„ฑ๋œ ๊ธ€์ž๊ฐ€ ์•„๋‹ˆ๋ผ๊ณ  ํŒ๋‹จํ•˜๊ฒŒ ๋œ๋‹ค.
์ด ๊ณผ์ •์—์„œ e.target.value๋Š” 'ํฌ๋„'์ด๊ธฐ ๋•Œ๋ฌธ์— data ๋ฐฐ์—ด์— ์ €์žฅ๋œ๋‹ค.

์œ„์™€ ๊ฐ™์€ ์ด์œ  ๋•Œ๋ฌธ์— ์—”ํ„ฐ๋ฅผ ๋ˆŒ๋ €๋‹ค๊ฐ€ ๋–ผ๋Š” ์ˆœ๊ฐ„์— ํ•œ๋ฒˆ ๋” ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ฒŒ ๋˜๊ณ ,
์ดˆ์„ฑ๊ณผ ์ค‘์„ฑ๋งŒ์œผ๋กœ ์ด๋ฃจ์–ด์ง„ '๋„'๋ฅผ ์™„์ „ํ•œ ๊ธ€์ž๋กœ ์ธ์‹ํ•˜๊ฒŒ ๋˜์–ด data์— ์ €์žฅ๋˜๋Š” ๊ฒƒ์ด๋‹ค.
๊ทธ ํ›„ ์ž…๋ ฅ์ด ์™„๋ฃŒ ๋˜์—ˆ๋‹ค๊ณ  ํŒ๋‹จํ•˜๊ณ  isComposing์„ false๋กœ ๋ณ€๊ฒฝ์‹œํ‚จ๋‹ค.

๋ฌธ์ œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

isComposing ์†์„ฑ ์ด์šฉํ•˜๊ธฐ

// ๋“ฑ๋ก ๋ฒ„ํŠผ ํด๋ฆญ
  const onClickAddTodo = (e) => {
    if (
      inputValue &&
      e.key === "Enter" &&
      e.nativeEvent.isComposing === false // <- โœจ ์ด๋ถ€๋ถ„ ์ถ”๊ฐ€
    ) {
      setTodoData((prev) => [
        ...prev,
        {
          id: Date.now(),
          content: inputValue,
          isEdit: false,
          isDone: false,
        },
      ]);
      setInputValue("");
    }
  };

์œ„์—์„œ ๊ณ„์† ์‚ดํŽด๋ดค๋˜ isComposing ์†์„ฑ์„ ์ด์šฉํ•ด์„œ ์—”ํ„ฐ๋ฅผ ๋ˆŒ๋ €๋‹ค ๋–ผ๋Š” ์ˆœ๊ฐ„์— isComposing = false๊ฐ€ ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ ๋•Œ ๋ฐ์ดํ„ฐ๊ฐ€ ์ถ”๊ฐ€๋˜๋„๋ก ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•ด์ฃผ์—ˆ๋‹ค.

onKeyUp ์‚ฌ์šฉํ•˜๊ธฐ

์‚ฌ์‹ค ์ฐพ์•„๋ณด๋ฉด ๋‹ค onKeyPress๋ฅผ ์‚ฌ์šฉํ•˜๋ผ๊ณ  ํ•˜์ง€๋งŒ.. ์ด์ œ๋Š” onKeyPress๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— onKeyUp์„ ์‚ฌ์šฉํ•ด๋ณด์•˜๋Š”๋ฐ ์ด๊ฒƒ๋„ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ๋˜์—ˆ๋‹ค!

onKeyUp์€ ํ‚ค๋ฅผ ๋ˆŒ๋ €๋‹ค๊ฐ€ ๋—„ ๋•Œ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ํ‚ค๋ณด๋“œ ์ด๋ฒคํŠธ ํ•จ์ˆ˜์ด๋‹ค.

์ด ๊ฒฝ์šฐ๋„ onKeyDown์ด๋ž‘ ๊ฒฐ๊ตญ ๋˜‘๊ฐ™์€๊ฑฐ ์•„๋‹๊นŒ? ์ƒ๊ฐํ–ˆ๋Š”๋ฐ ํ‚ค๋ฅผ ๋ˆŒ๋ €๋‹ค๊ฐ€ ๋–ผ๋Š” ์ˆœ๊ฐ„ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด์„œ ๊ทธ ์‹œ์ ์— ์ž…๋ ฅ๊ฐ’์€ ์ž…๋ ฅ์ด ์™„๋ฃŒ๋œ ์ƒํƒœ๋กœ ์ธ์‹์ด ๋œ๋‹ค.

๐Ÿ‘ฉ๐Ÿป‍๐Ÿ’ป ๋А๋‚€์ 

๊ทธ์ € 'ํ‚ค๋ฅผ ์ž…๋ ฅํ•  ๋•Œ ์ผ์–ด๋‚˜๋Š” ์ด๋ฒคํŠธ๋“ค์ด๋‹ค, onKeyDown์€ ํ‚ค๋ฅผ ๋ˆ„๋ฅธ ์ˆœ๊ฐ„์— ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  onKeyUp์€ ํ‚ค๋ฅผ ๋ˆŒ๋ €๋‹ค๊ฐ€ ๋–ผ๋Š” ์ˆœ๊ฐ„์— ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค

~

' ์ด์ •๋„๋กœ๋งŒ ์•Œ์•˜์ง€ ์ด๋ ‡๊ฒŒ ์ž์„ธํ•˜๊ฒŒ ํŒŒ๋ณธ ์ ์ด ์—†์–ด์„œ ํ—ท๊ฐˆ๋ฆฌ๊ณ  ์–ด๋ ค์› ์ง€๋งŒ ๊ต‰์žฅํžˆ ์žฌ๋ฏธ์žˆ์—ˆ๋‹ค.

์šด์˜์ฒด์ œ๋‚˜ ๋ธŒ๋ผ์šฐ์ €๋งˆ๋‹ค ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ๋„ ์‹ ๊ธฐํ•˜๊ณ  ํ•œ๊ธ€๊ณผ ์˜์–ด์˜ ์ž…๋ ฅ๋ฐฉ์‹ ์ฐจ์ด๊ฐ€ ๋™์ž‘๋ฐฉ์‹์— ์ด๋ ‡๊ฒŒ๋‚˜ ํฐ ์˜ํ–ฅ์„ ์ฃผ๋Š”์ง€ ๋ชฐ๋ž์–ด์„œ ์‹ ๊ธฐํ–ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์™œ ์šด์˜์ฒด์ œ๋งˆ๋‹ค ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€๋„ ๊ถ๊ธˆํ•ด์กŒ๋‹ค. (๋งฅ๋ถ์€ ๋ฏธ๊ตญ๊บผ๋ผ ๊ทธ๋Ÿฐ๊ฐ€?๐Ÿค”)

๊ฑฐ์˜ 5์‹œ๊ฐ„์„ ์ด๊ฒƒ๋งŒ ์ฐพ์•„๋ณด๊ณ  ์˜ˆ์ œ์ฝ”๋“œ ์จ๋ณด๊ณ  ์†์œผ๋กœ ์จ๋ณด๊ณ  ๊ทธ๋ ค๋ณด๊ณ  ํ•œ ๊ฒƒ ๊ฐ™์€๋ฐ 1๋…„๋™์•ˆ ๋งํ•  '์™œ?๋„๋Œ€์ฒด ์™œ?'๋ผ๋Š” ๋ง์„ ์˜ค๋Š˜ ๋‹คํ•œ ๊ฒƒ ๊ฐ™๋‹ค. ๋‹น๋ถ„๊ฐ„ ํฌ๋„์˜ ํฌ์ž๋„ ๋ณด๊ธฐ ์‹ซ์„ ์˜ˆ์ •(?)๐Ÿคฃ๐Ÿคฃ


์ฐธ๊ณ  ๋งํฌ
keydown ์ด๋ฒคํŠธ ํ•œ๊ธ€ ์ค‘๋ณต ์ž…๋ ฅ ํ˜„์ƒ
[JS] keydown/keyup์—์„œ ํ•œ๊ธ€ ์ž…๋ ฅ ์‹œ ํ•จ์ˆ˜๊ฐ€ ๋‘ ๋ฒˆ ์‹คํ–‰๋˜๋Š” ๊ฒฝ์šฐ

๋Œ“๊ธ€