Skip to content

Bootion Key Interaction

Namjin Kim edited this page Dec 14, 2020 · 1 revision

Bootion Key Interaction

Untitled

ํ•ด๋‹น ๋ฌธ์„œ๋Š”...

Bootion์˜ Key ์ž…๋ ฅ Interaction ์— ๋Œ€ํ•ด ์„ค๋ช… ํ•ฉ๋‹ˆ๋‹ค.

์™œ key Interaction์„ Custom ํ–ˆ๋‚˜์š”?

Browser๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ž…๋ ฅ๊ณผ ๊ด€๋ จ๋œ ํ›Œ๋ฅญํ•œ Interaction์„ ์ง€์› ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ €ํฌ Bootion์€ Notion์„ Clone ๋ฐ Upgrade ํ•œ ์›น ์„œ๋น„์Šค๋กœ ์ตœ๋Œ€ํ•œ Notion๊ณผ ๋น„์Šทํ•œ UX๋ฅผ ์ œ๊ณตํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— Notion์˜ ๋…์ž์ ์ธ Key Interaction ๋˜ํ•œ ์ง€์›ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ Customํ•œ ์ด์œ ๋Š” ๊ธฐ๋ฐ˜์ด ๋˜๋Š” ๊ตฌ์กฐ์™€ ๋ฐ€์ ‘ํ•œ ๊ด€๊ณ„๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ์•ž์„œ Block์— ๋Œ€ํ•ด ์•Œ ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

Block ์ด๋ž€?

Block์€ Notion์˜ ์ตœ์†Œ๋‹จ์œ„๋กœ ์ด Block์ด ๋ชจ์—ฌ์„œ ํ•˜๋‚˜์˜ Page๊ฐ€ ๋งŒ๋“ค์–ด ์ง‘๋‹ˆ๋‹ค. Block์€ ๋‹ค์–‘ํ•œ ํƒ€์ž…์ด ์žˆ์œผ๋ฉฐ Block๋“ค ๊ฐ„์—๋Š” ์œ„์น˜๋‚˜ ์ƒํƒœ์— ๋”ฐ๋ฅธ ์ƒํ˜ธ์ž‘์šฉ์ด ๋ฐœ์ƒํ•˜๊ณ  ์ž์œ ๋กœ์šด ๋ฐฐ์น˜๋ฅผ ์ง€์› ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ๋ธ”๋ก์˜ ์ƒํƒœ์— ๋”ฐ๋ผ key ์ž…๋ ฅ์— ๋”ฐ๋ฅธ ๋ฐ˜์‘์ด ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค.

๋ถˆ๊ฐ€ํ”ผํ•œ Custom

์œ„์™€ ๊ฐ™์€ ์ด์œ ๋กœ browser์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋ณธ ์ƒํ˜ธ์ž‘์šฉ์œผ๋กœ๋Š” Notion์˜ UX๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ์—๋Š” ๋ถ€์กฑํ•˜๋‹ค๊ณ  ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ key ์ž…๋ ฅ์— ๋”ฐ๋ฅธ Interaction์„ Custom ํ•˜๊ธฐ๋กœ ํ–ˆ์Šต๋‹ˆ๋‹ค.

Key Interaction ์— ๋Œ€์‘ํ•˜๊ธฐ ์œ„ํ•œ ์ƒํƒœ๊ด€๋ฆฌ

Bootion์€ Recoil์„ ํ†ตํ•ด ์ƒํƒœ๊ด€๋ฆฌ๊ฐ€ ์ด๋ฃจ์–ด์ง€๋ฉฐ ๋‹ค์Œ ๋‘ ์ƒํƒœ๋ฅผ ํ†ตํ•ด Block ์ •๋ณด๊ฐ€ ๊ด€๋ฆฌ ๋ฉ๋‹ˆ๋‹ค.

  • page์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” pageState
const pageState = atom<Page>({
  key: StateType.PAGE_STATE,
  default: (async () => (await fetchData()).page)(),
});

interface Page {
  id: IdType;
  title: string;
  rootId: IdType;
}
  • block์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” blockMapState
  • key ์ž…๋ ฅ์— ๋”ฐ๋ผ ๋ณต์ˆ˜์˜ ๋ธ”๋ก์— ๋Œ€ํ•œ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•ด์•ผํ•  ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋•Œ๋ฌธ์— ๋ชจ๋“  block์— ๋Œ€ํ•œ ์ ‘๊ทผ ๋ฐ ์ˆ˜์ •์ด ์šฉ์ดํ•œ ์ƒํƒœ๋ฅผ ๊ตฌํ˜„ํ•  ํ•„์š”๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ๋ชจ๋“  Block์˜ id๋ฅผ key๊ฐ’, block ๊ฐ์ฒด๋ฅผ value๋กœ ํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ์ƒํƒœ๊ฐ’์œผ๋กœ ๊ฐ€์ง€๊ฒŒํ•ด์„œ id๋ฅผ ํ†ตํ•ด ๋ชจ๋“  Block์— ๋Œ€ํ•œ ์ ‘๊ทผ ๋ฐ ์ˆ˜์ •์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ–ˆ์Šต๋‹ˆ๋‹ค.
const blockMapState = atom<BlockMap>({
  key: StateType.BLOCK_MAP_STATE,
  default: (async () => (await fetchData()).blockMap)(),
});

type BlockMap = { [key: string]: Block };

์™œ blockMapState๋ฅผ atomFamily๋กœ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•˜๋‚˜์š”?

recoil์—๋Š” atomFamily ๋ผ๋Š” ์ƒํƒœ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ์ƒํƒœ๋Š” atomํ•˜๊ณ  ๋น„์Šทํ•˜์ง€๋งŒ ์ฐจ์ด์ ์œผ๋กœ ๊ฐ ์ธ์Šคํ„ด์Šค๋งˆ๋‹ค ๊ณ ์œ ํ•œ key๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์œผ๋ฉฐ ์ด๋ฅผ ํ†ตํ•ด ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค์™€ ๊ตฌ๋ถ„ํ•ด์„œ ์ƒํƒœ๊ด€๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ blockMapState๋ฅผ atomFamily๋กœ ๊ตฌ์„ฑํ•  ์‹œ block์˜ id๋ฅผ key๋กœ ํ•œ๋‹ค๋ฉด Map ์ฒ˜๋Ÿผ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•จ๊ณผ ๋™์‹œ์— ์ธ์Šคํ„ด์Šค๋กœ ๊ฐœ๋ณ„์ƒํƒœ ๊ด€๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ ๊ธฐ์กด๊ตฌ์กฐ๋ณด๋‹ค ์šฉ์ดํ•ด๋ณด์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ...

react Hook์€ ์˜ค์ง React ํ•จ์ˆ˜๋‚ด์—์„œ๋งŒ ํ˜ธ์ถœ์ด ๊ฐ€๋Šฅ ํ•ฉ๋‹ˆ๋‹ค!

React ๊ณต์‹๋ฌธ์„œ์— ์˜ํ•˜๋ฉด react Hook์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ทœ์น™์„ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.

  1. ์ตœ์ƒ์œ„(at the Top Level)์—์„œ๋งŒ Hook์„ ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  2. ์˜ค์ง React ํ•จ์ˆ˜ ๋‚ด์—์„œ Hook์„ ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค

์œ„์˜ ๊ทœ์น™์— ์˜ํ•˜๋ฉด hook์˜ inner function ์—์„œ๋Š” ์ƒํƒœ๋ฅผ ๊ตฌ๋…ํ•˜๋Š”๊ฒŒ ๋ถˆ๊ฐ€๋Šฅ ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, atomFamily๋กœ blockMapState๋ฅผ ์ƒ์„ฑํ•  ๊ฒฝ์šฐ ํ•„์š”ํ•œ Block ๊ฐ์ฒด๋ฅผ ์ฆ‰์‹œ ๊ตฌ๋…ํ•ด์„œ ์–ป๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅ ํ•ฉ๋‹ˆ๋‹ค. ๋‹จ, inner function์ด ์•„๋‹Œ Custom Hook ๋‚ด์—์„œ Hook์„ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์€ ๊ฐ€๋Šฅ ํ•ฉ๋‹ˆ๋‹ค. ๋•Œ๋ฌธ์— ํ•„์š”ํ•œ ๋ชจ๋“  Block ์ •๋ณด๋ฅผ ๊ฐ๊ฐ ๋ฏธ๋ฆฌ ๊ตฌ๋…ํ•ด๋†“์œผ๋ฉด ๋˜์ง€ ์•Š์„๊นŒ ํ•˜๋Š” ์ƒ๊ฐ์ด ๋“ค ์ˆ˜ ์žˆ์ง€๋งŒ Notion์˜ ๋ธ”๋ก๊ฐ„ ์ƒํ˜ธ์ž‘์šฉ ๋ฒ”์ฃผ๊ฐ€ ๋„“์–ด์„œ ๊ฒฐ๊ตญ ๋ชจ๋“  ๋ธ”๋ก ์ •๋ณด๊ฐ€ ํ•„์š”ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ๋ชจ๋“  Block ๊ฐ์ฒด ์ ‘๊ทผ์ด ์šฉ์ดํ•œ ์ง€๊ธˆ์˜ BlockMap ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

Key Interaction ์„ ๊ด€๋ฆฌ ๋ฐ ์ ์šฉํ•˜๋Š” Hook

์œ„์—์„œ ์„ค๋ช…ํ•œ blockMapState๋ฅผ ํ†ตํ•ด block์˜ id๋ฅผ key๋กœ Block ๊ฐ์ฒด์— ์ ‘๊ทผ์ด ๊ฐ€๋Šฅ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์€ Key Interaction์— ๋”ฐ๋ผ Block์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•œ Custom Hook ์ž…๋‹ˆ๋‹ค.

  • Bootion์˜ key Interaction์„ ๊ด€๋ฆฌํ•˜๋Š” useCommand Custom Hook
  • Block์˜ ๊ตฌ์กฐ๋‚˜ ์ƒํƒœ ๋ณ€๊ฒฝ์„ ๊ด€๋ฆฌํ•˜๋Š” useManager Custom Hook
  • Block์˜ ๊ณ„์ธต ์ •๋ณด์™€ ์ ‘๊ทผ์„ ๊ด€๋ฆฌํ•˜๋Š” useFamily Custom Hook
  • Block์˜ ๊ตฌ์กฐ๋‚˜ ์ƒํƒœ ๋ณ€๊ฒฝ ์ด๋ ฅ์„ ๊ด€๋ฆฌํ•˜๋Š” useHistory Custom Hook

useCommand

useCommand ๋Š” ์‚ฌ์šฉ์ž์˜ key ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์•„ Bootion์—์„œ ์ œ๊ณตํ•˜๋Š” Key Interaction์„ ์ ์šฉํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” Custom Hook ์ž…๋‹ˆ๋‹ค. useCommand ๋Š” ๋ธ”๋ก ๊ตฌ์กฐ ๋ณ€๊ฒฝ์„ ์œ„ํ•ด ๊ธฐ์ค€์ด๋˜๋Š” block์˜ id๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›๋Š” useManager Custom Hook์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • ๊ธฐ์ค€์ด๋˜๋Š” ๋ธ”๋ก์€ ํ‚ค ์ž…๋ ฅ์ด ๋ฐœ์ƒํ•œ focus ๋œ Block ์ž…๋‹ˆ๋‹ค.

key ์ž…๋ ฅ์— ๋”ฐ๋ฅธ ๋™์ž‘ ๋ฐฉ์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. key ์ž…๋ ฅ์ด ๋ฐœ์ƒํ•˜๋ฉด Bootion์—์„œ ๋Œ€์‘ํ•ด์•ผํ•˜๋Š” key์ธ์ง€ ๊ฒ€์ฆ ํ•ฉ๋‹ˆ๋‹ค.
  2. ๋งŒ์•ฝ ๋งž๋‹ค๋ฉด ๊ธฐ๋ณธ ์ด๋ฒคํŠธ๋ฅผ ์ทจ์†Œํ•˜๊ณ  key๊ฐ’์„ useCommand์—์„œ ๋ฐ˜ํ™˜ํ•œ dispatcher ํ•จ์ˆ˜์— ๋„ฃ์–ด ์‹คํ–‰ ํ•ฉ๋‹ˆ๋‹ค.
  3. Block ๊ตฌ์กฐ์— ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ๋ฐœ์ƒํ•˜๋Š” ์ž…๋ ฅ์ผ ๊ฒฝ์šฐ useManager์—์„œ ๋ฐ˜ํ™˜ํ•œ startTransaction ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•ด Transaction์„ ์ดˆ๊ธฐํ™” ํ•ฉ๋‹ˆ๋‹ค.
  4. key ์ž…๋ ฅ์— ๋Œ€์‘ํ•˜๋Š” ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด useManager์—์„œ ๋ฐ˜ํ™˜ํ•œ BlockMap ์กฐ์ž‘ ํ•จ์ˆ˜๋ฅผ ์‹ฑํ–‰ํ•ด Transaction์— ๋ฐ˜์˜ ํ•ฉ๋‹ˆ๋‹ค.
  5. ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ Block์— ๋ฐ˜์˜ํ•˜๊ธฐ์œ„ํ•ด useManager์—์„œ ๋ฐ˜ํ™˜ํ•œ commitTransaction ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ ํ•ฉ๋‹ˆ๋‹ค.
  6. commit๊ณผ ๋™์‹œ์— useHistroy์— Transaction ์ •๋ณด๊ฐ€ ์ €์žฅ ๋ฉ๋‹ˆ๋‹ค.
  7. Transaction์— ์ ์šฉ๋œ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด Block์— ๋ฐ˜์˜ ๋ฉ๋‹ˆ๋‹ค.

keyinteraction

Key Interaction ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ˆœ์„œ๋„

Transaction? ๊ทธ๋ƒฅ ๋ฐ”๋กœ Block์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด ๋˜์ง€ ์•Š๋‚˜์š”?

set ํ•จ์ˆ˜๋กœ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•  ๊ฒฝ์šฐ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ํ˜ธ์ถœ๊ณผ ๋™์‹œ์— ๋ฐ˜์˜๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ set ํ•จ์ˆ˜ ํ˜ธ์ถœํ›„ ์ƒํƒœ๋ฅผ ์ฝ์œผ๋ฉด ๋ณ€๊ฒฝ ์ „ ์ƒํƒœ๋ฅผ ์ฝ๊ฒŒ๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ ํ•ฉ๋‹ˆ๋‹ค. Transaction์€ ์œ„์™€ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋ณต์‚ฌํ•œ blockMap์— ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๋ฐ˜์˜ํ•˜๊ณ  commit ์‹œ ์ผ๊ด„ ๋ฐ˜์˜ํ•˜๋Š” ๋กœ์ง์œผ๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋•Œ๋ฌธ์— ๋ธ”๋ก์„ ํ•˜๋‚˜๋งŒ ์ˆ˜์ •ํ•˜๋ฉด ๋  ๊ฒฝ์šฐ์—๋Š” Transaction์„ ๊ฒฝ์œ ํ•˜์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋Œ€๋ถ€๋ถ„์˜ ์ˆ˜์ •์‚ฌํ•ญ์€ ๋ณต์ˆ˜์˜ ๋ธ”๋ก์— ๋Œ€ํ•œ ์ƒํƒœ๋ณ€๊ฒฝ์œผ๋กœ ์ด๋ฃจ์–ด์ง€๋ฏ€๋กœ Transaction์„ ํ†ตํ•ด ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๋ฐ˜์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

useManager

useManager ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์€ block์˜ id๋ฅผ ๊ธฐ์ค€์œผ๋กœ block์˜ ์ƒํƒœ์™€ ๊ตฌ์กฐ๋ณ€๊ฒฝ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” Custom Hook ์ž…๋‹ˆ๋‹ค. useManager ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์€ block์˜ id์™€ ๊ด€๋ จ๋œ block ์ •๋ณด๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด useFamily Custom Hook์„ ์‚ฌ์šฉ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ redo, undo ์— ๋Œ€์‘ํ•˜๊ธฐ์œ„ํ•ด useHistory Custom Hook์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์œ„์—์„œ ์„ค๋ช…ํ•œ ๋ฐ”์™€ ๊ฐ™์ด ์ง€์—ญ๋ณ€์ˆ˜๋กœ transaction ์ด๋ผ๋Š” Mutableํ•œ ๋ณ€์ˆ˜๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ๋ณ€์ˆ˜๋Š” blockMap์„ ๊ฐ’์œผ๋กœ ๊ฐ€์ง€๋ฉฐ block์˜ ์ƒํƒœ๋ฅผ ํ•ด์•ผํ•˜๋Š” ์‚ฌํ•ญ์€ transaction ๋ณ€์ˆ˜์— ๋ฐ˜์˜ ๋ฉ๋‹ˆ๋‹ค. ๊ด€๋ จ ํ•จ์ˆ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • startTransaction์„ ํ†ตํ•ด transaction ๋ณ€์ˆ˜๋ฅผ blockMap์œผ๋กœ ์ดˆ๊ธฐํ™” ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • commitTransaction์„ ํ†ตํ•ด transaction ์— ์ ์šฉ๋œ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ blockMapState์— ๋ฐ˜์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ํ˜„์žฌ transaction ์ •๋ณด๊ฐ€ useHistory์˜ ์ด๋ ฅ์ •๋ณด์— ์ถ”๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

useFamily

useFamily๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์€ block์˜ id๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ž์‹ , ๋ถ€๋ชจ, ์กฐ๋ถ€๋ชจ, ์ž์‹, ํ˜•์ œ๋“ค ๋“ฑ์— ๋Œ€ํ•œ ์ƒํƒœ์™€ ํŠน์ •์กฐ๊ฑด์— ๋ถ€ํ•ฉํ•˜๋Š” Block ๊ฐ์ฒด๋ฅผ ํƒ์ƒ‰ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” Hook ์ž…๋‹ˆ๋‹ค.

  • Notion์€ Block์˜ ์ƒํƒœ์™€ ์ž…๋ ฅ์— ๋”ฐ๋ผ ์ฃผ๋ณ€ Block์— ์˜ํ–ฅ์„ ๋ผ์นฉ๋‹ˆ๋‹ค. useFamily๋Š” ํ•ด๋‹น Block ๋“ค์„ ํƒ์ƒ‰ํ•˜๊ธฐ ์œ„ํ•œ ํ•จ์ˆ˜๋“ค์„ ์ง€์› ํ•ฉ๋‹ˆ๋‹ค.

Block ๊ตฌ์กฐ ๋ณ€๊ฒฝ ํ›„ Focus ํ• ๋‹น

key ์ž…๋ ฅ๊ณผ hook๋“ค์„ ํ†ตํ•ด Block์˜ ๊ตฌ์กฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด focus๋œ ๋Œ€์ƒ์„ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊น๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด์„œ๋Š” focus๋œ block์˜ ์ •๋ณด๋ฅผ state๋กœ ๊ด€๋ฆฌํ•  ํ•„์š”๊ฐ€ ์žˆ๋Š”๋ฐ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

  1. React๋Š” ์ž์ฒด์ ์œผ๋กœ focus๋ฅผ ์ฃผ๊ธฐ์œ„ํ•œ props๋‚˜ ํ•จ์ˆ˜๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  2. ์œ„์™€ ๊ฐ™์€ ์ด์œ ๋กœ DOM์˜ focus ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด useRef๋กœ DOM์„ ์–ป์„ ํ•„์š”๊ฐ€ ์ƒ๊น๋‹ˆ๋‹ค.
  3. ๊ทธ๋ฆฌ๊ณ  ์ด๋ ‡๊ฒŒ ์–ป์€ ref๋Š” ์ „์—ญ์œผ๋กœ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ๊นŒ์ง€ ๋„๋‹ฌํ•˜๋ฉด Block์˜ ref๋ฅผ ์ƒํƒœ๋กœ ๊ด€๋ฆฌํ•ด์•ผํ•  ํ•„์š”์„ฑ์„ ๋Š๋‚๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ...

DOM์€ React State๋กœ ๊ด€๋ฆฌํ•˜๋ฉด ์•ˆ๋ฉ๋‹ˆ๋‹ค!

React State๋กœ ๊ด€๋ฆฌ๋˜๊ธฐ ์‹œ์ž‘ํ•˜๋Š” ๊ฐ’๋“ค์€ immutable ํ•ด์ง‘๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ DOM์„ state๋กœ ๊ด€๋ฆฌํ•  ์‹œ ํ•ด๋‹น DOM ๋“ค์€ ์ˆ˜์ •์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด ์ƒํƒœ์—์„œ ํ•ด๋‹น DOM ๋“ค์ด ํฌํ•จ๋œ Component๊ฐ€ ์‚ญ์ œ๋  ์‹œ ReactDom์—์„œ ์•„๋ž˜์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒ ํ•ฉ๋‹ˆ๋‹ค.

Untitled 1

์›์ธ์€ ReactDom์—์„œ ํ•ด๋‹น Component๋ฅผ ์‚ญ์ œํ•˜๊ธฐ์œ„ํ•ด ref์˜ current ๊ฐ’์„ null๋กœ ๋ฐ”๊พธ๋ ค ๋กœ์ง์— ์žˆ์Šต๋‹ˆ๋‹ค. ์ˆ˜์ •ํ•  ์ˆ˜ ์—†๊ฒŒ๋œ DOM ๊ฐ์ฒด๋ฅผ ์ˆ˜์ •ํ•˜๋ ค ํ•œ ๊ฒƒ์ด์ง€์š”.

๊ทธ๋Ÿฌ๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ์š”?

ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์€ ๊ฐ„๋‹จ ํ•ฉ๋‹ˆ๋‹ค. block์— ๋Œ€ํ•œ DOM ๊ฐ์ฒด๋ฅผ ์ „์—ญ์œผ๋กœ ์ ‘๊ทผํ•  ํ•„์š”์„ฑ์€ ์—ฌ์ „ํžˆ ์žˆ์ง€๋งŒ ์ด๋ฅผ state๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์—†์„๋ฟ ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ Object์— ๋‹ด์•„์„œ ์ „์—ญ์œผ๋กœ ์ ‘๊ทผํ•˜๊ฒŒํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

const blockRefState: { [id: string]: MutableRefObject<any> } = {};

blockRefState๋Š” ๋ชจ๋“  Block์— ๋Œ€ํ•œ DOM ๊ฐ์ฒด์ ‘๊ทผ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋Š” ์ฑ…์ž„๋งŒ ์žˆ์„๋ฟ ๊ตฌ๋…์„ ํ†ตํ•ด Component์˜ ํ‘œ์‹œ๋‚ด์šฉ์„ ๋งค๋ฒˆ ๊ฐฑ์‹ ํ•ด์•ผํ•˜๋Š” ์˜์กด์„ฑ์ด ์—†์œผ๋ฏ€๋กœ ์œ„์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•ด๋„ ๋œ๋‹ค๋Š” ๊ฒฐ๋ก ์— ์ด๋ฅด๋ €์Šต๋‹ˆ๋‹ค.

Block ์ƒ์„ฑ ํ›„ Focus ํ• ๋‹น

Enter ํ‚ค ์ž…๋ ฅ ์‹œ ํ˜„์žฌ Focus๋œ Block์˜ ์ฒซ๋ฒˆ์งธ ์ž์‹ ํ˜น์€ ๋‹ค์Œํ˜•์ œ์— ์‹ ๊ทœ๋ธ”๋ก์ด ์‚ฝ์ž… ๋ฉ๋‹ˆ๋‹ค. ์‚ฝ์ž…ํ›„์—๋Š” ์‹ ๊ทœ๋ธ”๋ก์— Focus๋ฅผ ํ• ๋‹นํ•ด์•ผ ํ•˜๋Š”๋ฐ ํ•ด๋‹น ๋กœ์ง์„ ์ˆ˜ํ–‰์ค‘์ธ useCommand Hook ๋‚ด์—์„œ๋Š” ์•„์ง ReactDom์— ์˜ํ•ด ์‹ ๊ทœ๋ธ”๋ก์ด ์ƒ์„ฑ๋˜๊ธฐ ์ „์ด๋ฏ€๋กœ blockRefState์—๋Š” ํ•ด๋‹น Block์˜ DOM ๊ฐ์ฒด๊ฐ€ ๋‹ด๊ฒจ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ์‹ ๊ทœ๋ธ”๋ก์ด ๋žœ๋”๋ง๋จ๊ณผ ๋™์‹œ์— ์ž์‹ ์ด focus๋œ ๋ธ”๋ก์ž„์„ ์•Œ ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

focusState

์œ„์™€ ๊ฐ™์€ ํ•„์š”๊ฐ€ ์žˆ์–ด focusState๋ฅผ ํ†ตํ•ด ํ˜„์žฌ focus๋œ Block์˜ id๋ฅผ ๊ด€๋ฆฌํ•˜๊ฒŒ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  Block์€ focusState๋ฅผ ๊ตฌ๋…ํ•˜๊ณ  focusId๊ฐ€ ์ž์‹ ์˜ id์ธ์ง€ ๊ฒ€์ฆํ•˜๋ฉฐ ์ž์‹ ์˜ id ์ผ ๊ฒฝ์šฐ ์ž์‹ ํ•œํ…Œ focus๋ฅผ ์ค๋‹ˆ๋‹ค. ๋•Œ๋ฌธ์— focusState์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•œ๋‹ค๋Š” ๊ฒƒ์€ ๋ณ€๊ฒฝํ•œ id๋ฅผ ๊ฐ€์ง„ Block์— focus๋ฅผ ์ฃผ๋Š” ๊ฒƒ์ด ๋ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น ๋ฐฉ์•ˆ์„ ํ†ตํ•ด Hook๋‚ด์—์„œ focusState์˜ ์ƒํƒœ๊ฐ’์„ ์‹ ๊ทœ๋ธ”๋ก์˜ id๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋žœ๋”๋ง ์‹œ focus๊ฐ€ ํ• ๋‹น๋˜๊ฒŒ ํ–ˆ์Šต๋‹ˆ๋‹ค.

Caret ์œ„์น˜ ์กฐ์ž‘

Interaction์— ์˜ํ•ด focus๊ฐ€ ๋ณ€๊ฒฝ๋  ๊ฒฝ์šฐ caret์˜ ์œ„์น˜๋„ ์กฐ์ •๋˜์–ด์•ผํ•  ํ•„์š”๊ฐ€ ์ƒ๊น๋‹ˆ๋‹ค. ๋ณดํ†ต ๋‹ค์Œ์˜ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. focus ๋œ ๋ธ”๋ก์˜ 0๋ฒˆ์งธ offset์— caret์ด ๋ฐฐ์น˜๋˜์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ
  2. focus๋œ ๋ธ”๋ก์˜ ๋งˆ์ง€๋ง‰ offset์— caret์ด ๋ฐฐ์น˜๋˜์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ
  3. ์ด์ „์— focus๋œ ๋ธ”๋ก์˜ offset์ด ํ˜„์žฌ focus๋œ ๋ธ”๋ก์— ๋ฐ˜์˜๋˜์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ

์œ„์™€ ๊ฐ™์€ ํ•„์š”์„ฑ์— ์˜ํ•ด Caret Offset์„ ์กฐ์ •ํ•˜๊ธฐ ์œ„ํ•ด์„œ Selection API๋ฅผ ์‚ฌ์šฉ ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • Selection API ๋Š” ํ˜„์žฌ Caret ์˜ ์˜ํ–ฅ์„ ๋ฐ›๊ณ  ์žˆ๋Š” Node ์™€ offset ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • window ํ˜น์€ document ๊ฐ์ฒด์—์„œ getSelection() ํ˜ธ์ถœ์„ ํ†ตํ•ด ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • Selection ๊ฐ์ฒด์˜ collapse ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด caret offset ์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Selection API๋ฅผ ์ด์šฉํ•ด Caret ์ •๋ณด๋ฅผ ์ฝ๊ฑฐ๋‚˜ ์„ค์ •ํ•˜๋Š”๊ฒŒ ๊ฐ€๋Šฅํ•ด์กŒ์ง€๋งŒ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ ํ–ˆ์Šต๋‹ˆ๋‹ค.

rerendering, focus ๋ณ€๊ฒฝ์— ๋”ฐ๋ฅธ caret ์œ„์น˜ ๋ณ€๊ฒฝ

Block Component๊ฐ€ rerendering ๋˜๊ฑฐ๋‚˜ focus๊ฐ€ ๋ณ€๊ฒฝ๋  ๊ฒฝ์šฐ ๊ธฐ๋ณธ Interaction์— ์˜ํ•ด caret offset์ด 0์œผ๋กœ ์„ค์ • ๋ฉ๋‹ˆ๋‹ค. ์ด ์ƒํƒœ์—์„œ Bootion์˜ Key Interaction์ด ๋ฐ˜์˜๋˜๋ฏ€๋กœ ๊ธฐ๋Šฅ์ƒ์œผ๋กœ๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์ง€๋งŒ UX ์ธก๋ฉด์—์„œ๋Š” ์ด์ „ focus Block์˜ ๋งจ ์•ž์œผ๋กœ caret์ด ๋‹น๊ฒจ์กŒ๋‹ค๊ฐ€ ์›๋ž˜ ๋ฐฐ์น˜๋˜์–ด์•ผํ•  ์œ„์น˜๋กœ ์žฌ๋ฐฐ์น˜ ๋˜๋Š” ํ˜„์ƒ์„ ๊ฒช๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์–ด๋–ป๊ฒŒํ•ด์•ผ ์ด๋Ÿฌํ•œ ํ˜„์ƒ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”? ๐Ÿค”

ํ•ด๋‹น ํ˜„์ƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ์— ๋ฐœ์ƒ ํ•ฉ๋‹ˆ๋‹ค.

  1. Block Component๊ฐ€ ์ƒˆ๋กœ ์ƒ์„ฑ๋  ๊ฒฝ์šฐ
  2. Block Component ๋‚ด ๋กœ์ง์— ์˜ํ•ด focus๊ฐ€ ์ž์‹ ์—๊ฒŒ ํ• ๋‹น๋  ๊ฒฝ์šฐ

์ฆ‰ ๋žœ๋”๋ง ํ›„ focus๊ฐ€ ์žฌํ• ๋‹น๋˜์–ด์„œ caret offset์ด 0์œผ๋กœ ์„ค์ • ๋˜์—ˆ๋Š”๋ฐ caret ์œ„์น˜ ๋ณ€๊ฒฝ๋กœ์ง์ด ์ ์šฉ๋˜์–ด์„œ caret ์œ„์น˜๊ฐ€ ์™”๋‹ค๊ฐ”๋‹ค ํ•˜๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ์•„๋ž˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ ์œ„์˜ ๊ฒฝ์šฐ์— ๊ธฐ์กด focus๋œ Block์˜ caret์„ blur(focus๋ฅผ ์žƒ๊ฒŒ) ํ•˜๊ณ  ๋žœ๋”๋ง ์ดํ›„์— focus๋œ block์— caret์ด ๋ฐฐ์น˜ ๋  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

const setFocus = (targetBlock: Block) => {
    if (!targetBlock) {
      return null;
    }
    const beforeOffset = window.getSelection().focusOffset;
    setFocusId(targetBlock.id);
    const targetRef = blockRefState[targetBlock.id];
    targetRef
      ? targetRef.current.focus()
      : blockRefState[block.id].current.blur();
    return beforeOffset;
  }; 

์ด๋ ‡๊ฒŒ focus์™€ caret ์— ๋Œ€ํ•œ UX๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ์ฒ˜๋Ÿผ ๊ตฌํ˜„์˜ ํ‹€์ด ์žกํžˆ๋ฉด์„œ UX์™€ ๋ฐ€์ ‘ํ•œ ํฐ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ ํ–ˆ์Šต๋‹ˆ๋‹ค.

์—ฐ์†๋œ key ์ž…๋ ฅ๊ณผ ๋žœ๋”๋ง ์†๋„

Key ์ž…๋ ฅ์ด ์—ฐ์†์œผ๋กœ ๋น ๋ฅด๊ฒŒ ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ ๋žœ๋”๋ง ์†๋„๊ฐ€ key Interaction ์ ์šฉ ์†๋„๋ฅผ ๋ชป๋”ฐ๋ผ์žก์•„ ํ™”๋ฉด์ด ๋ฉˆ์ถ”๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•œ ๊ฒƒ ์ž…๋‹ˆ๋‹ค. ์‹ฌ์ง€์–ด Enter Key Interaction์˜ ๊ฒฝ์šฐ ์ƒˆ๋กœ์šด ๋ธ”๋ก์ƒ์„ฑ ์†๋„๊ฐ€ focus ์ƒํƒœ ๋ณ€๊ฒฝ์†๋„๋ฅผ ๋ชป๋”ฐ๋ผ์žก๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ด์„œ useCommand(useCommand๋Š” focus ๋œ ๋ธ”๋ก์„ ๊ธฐ์ค€์œผ๋กœ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ ์ž…๋‹ˆ๋‹ค.)์—์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ •๋„ ์˜€์Šต๋‹ˆ๋‹ค. ๋•Œ๋ฌธ์— Key Interaction์ด ์ ์šฉ๋œ ํ›„์— ์ƒˆ๋กœ์šด Key ์ž…๋ ฅ์„ ๋ฐ›๊ฒŒํ•  ํ•„์š”๊ฐ€ ์ƒ๊ฒผ์Šต๋‹ˆ๋‹ค.

Key Interaction๊ณผ throttling

ํ•ด๋‹น ๋ฌธ์ œ๋Š” UX์™€ ๊ด€๋ จํ•ด ์ž์ฃผ ์–ธ๊ธ‰๋˜๋Š” ์‚ฌํ•ญ์ด๋ฉฐ throttling ์ด ํ•ด๊ฒฐ์ฑ…์œผ๋กœ ๊ผฝํž™๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ Lodash ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ throttle ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ ์ž ์‹œ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค ํ•˜์ง€๋งŒ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

  1. Bootion์€ Component๋ฅผ ํ•จ์ˆ˜ํ˜•์œผ๋กœ ๊ตฌํ˜„ํ•˜๋ฏ€๋กœ ๋žœ๋”๋ง๋  ๋•Œ ๋งˆ๋‹ค ์ง€์—ญ๋ณ€์ˆ˜๋“ค์„ ๋‹ค์‹œ ์ƒ์„ฑ ํ•ฉ๋‹ˆ๋‹ค.
  2. ๊ทธ๋Ÿฌ๋ฏ€๋กœ key ์ž…๋ ฅ์— throttle์„ ์ ์šฉํ•ด๋„ ๋ฆฌ๋žœ๋”๋ง ๋  ๋•Œ throttle ๋œ ์ƒํƒœ์ธ์ง€์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ๋‚จ์ง€ ์•Š์œผ๋ฏ€๋กœ throttle์ด ์ ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  3. throttle์„ ์‚ฌ์šฉํ•˜๋Š” ์ด๋ฒคํŠธ ํ•จ์ˆ˜๋ฅผ useRef๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ์•ˆ์ด ์žˆ์ง€๋งŒ ๋‚ด๋ถ€์—์„œ useCommand๊ฐ€ ๋ฐ˜ํ™˜ํ•œ dispatcher๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ useCommand์™€ ๊ด€๋ จ๋œ ์ƒํƒœ์— ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ๋ฐœ์ƒํ•จ์— ๋”ฐ๋ผ dispatcher๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊ฒจ์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒ ํ•ฉ๋‹ˆ๋‹ค.

๊ฒฐ๊ตญ throttle ์ƒํƒœ์ •๋ณด๊ฐ€ ์ €์žฅ๋˜์ง€ ์•Š์•„ ํ•ด๋‹น ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๊ณ  ๊ฒฐ๋ก ์„ ๋‚ด๋ ธ์Šต๋‹ˆ๋‹ค.

Custom Throttle

์œ„์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ ํ˜„์žฌ throttle ์ƒํƒœ์— ๋Œ€ํ•œ ์ƒํƒœ๊ด€๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๊ณ  ํŒ๋‹จ์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

const throttleState = {
  isThrottle: false,
};

์œ„์˜ ์ƒํƒœ๋ฅผ ํ†ตํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ตฌ์กฐ๋กœ Custom throtting์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
    const { focusNode, focusOffset } = window.getSelection();
    if (throttleState.isThrottle) {
      event.preventDefault();
    } else if (/* Bootion์ด ๋‹ค๋ค„์•ผํ•  key ์ž…๋ ฅ์ธ๊ฐ€? */) {
      throttleState.isThrottle = true;
      event.preventDefault();
      setImmediate(() => {
        Dispatcher(event.key);
        throttleState.isThrottle = false;
      });
    }
  };

ํ•ด๋‹น ๋กœ์ง์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ ˆ์ฐจ๋กœ ์ง„ํ–‰ ๋ฉ๋‹ˆ๋‹ค.

  1. throttleState์˜ isThrottle์ด false ์ผ ๊ฒฝ์šฐ์—๋งŒ Key Interaction์ด ๋ฐœ์ƒ ํ•ฉ๋‹ˆ๋‹ค.
  2. key Interaction์ด ๋ฐœ์ƒํ•ด์•ผํ•  ๊ฒฝ์šฐ isThrottle ๊ฐ’์ด true๊ฐ€ ๋˜์–ด ์ดํ›„ ๋ฐœ์ƒํ•˜๋Š” key ์ž…๋ ฅ์„ ๋ฒ„๋ฆฝ๋‹ˆ๋‹ค.
  3. setImmediate ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ฝœ๋ฐฑํ•จ์ˆ˜์—์„œ dispatcher๋ฅผ ์‹คํ–‰ ํ•ฉ๋‹ˆ๋‹ค. ์‹คํ–‰์ด ์™„๋ฃŒ๋˜๋ฉด isThrottle์˜ ๊ฐ’์„ false๋กœ ๋ณ€๊ฒฝํ•ด์„œ key ์ž…๋ ฅ์— ๋”ฐ๋ผ Key Interaction์ด ๋ฐœ์ƒํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

์œ„์˜ ๋กœ์ง์„ ํ†ตํ•ด Key Interaction ์ ์šฉ์ด ์™„๋ฃŒ๋œ ์ดํ›„ ๋‹ค์Œ Key Interaction ์ ์šฉ์„ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.