๊ด€๋ฆฌ ๋ฉ”๋‰ด

C-log

[FE]๋‚˜๋งŒ์˜ ์‹œํ—˜์ง€์˜ ์—๋””ํ„ฐ์™€ ํˆด๋ฐ”๋ฅผ ์ง์ ‘ ์ œ์ž‘ํ•œ๋‹ค.(๊ธฐ๋ณธ ํˆด๋ฐ” ์ œ์ž‘) ๋ณธ๋ฌธ

๐Ÿ’ป๊ฐœ๋ฐœ ๋…ธํŠธ/๋‚˜๋งŒ์˜ ์‹œํ—˜์ง€

[FE]๋‚˜๋งŒ์˜ ์‹œํ—˜์ง€์˜ ์—๋””ํ„ฐ์™€ ํˆด๋ฐ”๋ฅผ ์ง์ ‘ ์ œ์ž‘ํ•œ๋‹ค.(๊ธฐ๋ณธ ํˆด๋ฐ” ์ œ์ž‘)

4:Bee 2024. 3. 22. 16:06
728x90

์•ž์„œ ํฌ์ŠคํŒ…์—์„œ react-quill์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์ง์ ‘ ์—๋””ํ„ฐ์™€ ํˆด๋ฐ”๋ฅผ ์ œ์ž‘ํ•˜๊ธฐ๋กœ ๊ฒฐ์ • ํ–ˆ๋‹ค. ๊ทธ๋Ÿฌ๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‘๊ฐ€์ง€๋ฅผ ์•Œ์•„์•ผ ํ•œ๋‹ค. ์ฒซ ๋ฒˆ์งธ๋กœ contentEditable๊ณผ execCommand์ด๋‹ค. 

# contentEditable

contentEditable์€ HTML ์š”์†Œ์˜ ์†์„ฑ(attribute) ์ค‘ ํ•˜๋‚˜๋กœ, ์‚ฌ์šฉ์ž๊ฐ€ ํ•ด๋‹น ์š”์†Œ์˜ ๋‚ด์šฉ์„ ์ง์ ‘ ํŽธ์ง‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ํ™œ์„ฑํ™”ํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์›ํ•˜๋Š” ํƒœ๊ทธ์— contentEditable="true"๋ฅผ ๊ธฐ์ž…ํ•˜๊ฒŒ ๋˜๋ฉด ์›น ํŽ˜์ด์ง€๋‚˜ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ํ…์ŠคํŠธ ์ž…๋ ฅ ์ƒ์ž๋‚˜ ํŽธ์ง‘ ๊ฐ€๋Šฅํ•œ ์ปจํ…์ธ ๊ฐ€ ๋œ๋‹ค. ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.


      <div
        className="editor"
        contentEditable="true"
        dangerouslySetInnerHTML={{ __html: content }}
        ref={editorRef}
        style={{ padding: '16px 24px', border: '1px solid #D6D6D6', borderRadius: '4px' }}
      />
 

๋”ฐ๋ผ์„œ divํƒœ๊ทธ๊ฐ€ ํŽธ์ง‘์„ ํ• ์ˆ˜ ์žˆ๊ฒŒ ๋œ ๊ฒƒ์ด๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅ์„ ์ง์ ‘ ๊ธฐ์ž…ํ•  ์ˆ˜ ์žˆ๋Š” ์—๋””ํ„ฐ๋กœ ์ง€์ •์ด ๋œ ๊ฒƒ์ด๋‹ค. ์—ฌ๊ธฐ์„œ dangerouslySetInnerHTML={{ __html: content }}๋Š” content๋ผ๋Š” ๋ณ€์ˆ˜์— ๋“ค์–ด ์žˆ๋Š” HTML ๋ฌธ์ž์—ด์„ ํ•ด๋‹น <div> ์š”์†Œ์˜ ๋‚ด๋ถ€ HTML๋กœ ์„ค์ •ํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ content์— ์žˆ๋Š” HTML์ด <div> ๋‚ด๋ถ€์— ๋ Œ๋”๋ง๋œ๋‹ค. ์ฆ‰, content์—๋Š” HTML ๋ฌธ์ž์—ด๋กœ ์ €์žฅ์ด ๋˜์–ด ์žˆ๋Š”๋ฐ ์ด๊ฒƒ์„ ์ผ๋ฐ˜ ๋ฌธ์ž์—ด๋กœ ๋ Œ๋”๋ง ํ•˜๊ธฐ ์œ„ํ•ด์„œ dangerouslySetInnerHTML๋กœ ๋ Œ๋”๋ง์ด ๋˜๋Š” ๊ฒƒ์ด๋‹ค. ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ๋Š” HTML๋ฌธ์ž์—ด๋กœ ์ž˜ ์ €์žฅ์ด๋˜๋Š”์ง€ ์ž„์‹œ๋กœ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์•„๋ž˜ divํƒœ๊ทธ๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ํ™•์ธ ํ•ด๋ณด๊ณ  ์žˆ๋‹ค.

   <div>
        <p>Content (HTML string):</p>
        {content}
   </div>

# ref={editorRef} ๊ทธ๋ฆฌ๊ณ  useRef

* ref={editorRef

ref={editorRef}์˜ ref๋Š” react์—์„œ ์‚ฌ์šฉ๋˜๋Š” ํŠน๋ณ„ํ•œ ์†์„ฑ์œผ๋กœ, react ์—˜๋ฆฌ๋จผํŠธ๋‚˜ ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด DOM ์š”์†Œ์— ์ง์ ‘์ ์œผ๋กœ ์ ‘๊ทผํ•˜๊ฑฐ๋‚˜ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.

* useRef

useRef๋Š” react์—์„œ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ๋„ ๊ฐ’์ด ๋ณ€ํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” Hook์ด๋‹ค. ์ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ DOM ์š”์†Œ์— ์ ‘๊ทผํ•˜๊ฑฐ๋‚˜, ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ  ๊ฐ’์ด ๋ณ€ํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค. ์—ฌ๊ธฐ์„œ const editorRef = useRef(null);์€ ์ดˆ๊ธฐ๊ฐ’์ด null์ธ ์ƒˆ๋กœ์šด ref๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด editorRef๋Š” <div> ์š”์†Œ์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ๋ณ€์ˆ˜์ด๋‹ค. useRef๋ฅผ ํ†ตํ•ด ์ƒ์„ฑ๋œ editorRef๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•ด๋‹น ๋ณ€์ˆ˜๋ฅผ ํ†ตํ•ด <div> ์š”์†Œ์— ์ง์ ‘์ ์œผ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰, useRef๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ ๋‚ด๊ฐ€ ์›ํ•˜๋Š” DOM ์š”์†Œ์— ref๋ฅผ ํ†ตํ•ด ์ฐธ์กฐ๋ฅผ ํ•ด์„œ DOM์š”์†Œ์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด์ œ ์•ž์œผ๋กœ eidtorRef๋ฅผ ๊ณ„์† ํ•ด์„œ ์ฐธ์กฐํ•˜๊ฒŒ ๋˜๋Š” ํ•จ์ˆ˜๋“ค์ด ๋“ฑ์žฅํ•  ๊ฒƒ์ด๋‹ค. ์œ ์‹ฌํžˆ ํ™•์ธํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

# ํˆด๋ฐ”๋ฅผ ์ œ์ž‘ํ•œ๋‹ค.

์•ž์„œ ์šฐ๋ฆฌ๋Š” contentEditable์„ ์ด์šฉํ•ด์„œ ํˆด์„ ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ๋Š” ํ™˜๊ฒฝ์„ ๊ตฌ์„ฑํ–ˆ๋‹ค ์ด์ œ ๊ฐ๊ธฐ ํ•„์š”ํ•œ ๋ฒ„ํŠผ๋“ค์„ ๊ตฌํ˜„ ํ•ด๋ณด๊ฒ ๋‹ค.

 
   <div className="editor-menu" style={{ marginBottom: '10px' }}>
        <button onClick={handleBoldClick} style={{ marginRight: '5px' }}><b>B</b></button>
        <button onClick={handleItalicClick} style={{ marginRight: '5px' }}><i>I</i></button>
        <button onClick={handleUnderlineClick} style={{ marginRight: '5px' }}><u>U</u></button>
        <button onClick={handleStrikeClick} style={{ marginRight: '5px' }}><s>S</s></button>
        <button onClick={handleOrderedListClick} style={{ marginRight: '5px' }}>OL</button>
        <button onClick={handleUnorderedListClick} style={{ marginRight: '5px' }}>UL</button>
        <button onClick={handleUploadImageClick} style={{ marginRight: '5px' }}>IMG</button>
    </div>
 

์œ„์™€ ๊ฐ™์€ ๋ฒ„ํŠผ๋“ค์„ ๊ตฌํ˜„ํ•˜๊ณ  ๊ฐ๊ธฐ ํšจ๊ณผ๋ฅผ ์ค„ ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜๋“ค์„ ๊ตฌํ˜„ ํ•ด๋ณด์•˜๋‹ค. 

 
  const focusEditor = () => {
    editorRef.current.focus({ preventScroll: true });
  };

  // execCommand๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ƒ์„ฑ๋œ ์ฝ”๋“œ
  function setStyle(style) {
    document.execCommand(style);
    focusEditor();
  }
 
  const handleBoldClick = () => {
    setStyle('bold');
    focusEditor();
  };

  const handleItalicClick = () => {
    setStyle('italic');
    focusEditor();
  };

  const handleUnderlineClick = () => {
    setStyle('underline');
    focusEditor();
  };

  const handleStrikeClick = () => {
    setStyle('strikeThrough');
    focusEditor();
  };

  const handleOrderedListClick = () => {
    setStyle('insertOrderedList');
    focusEditor();
  };
 
const handleUnorderedListClick = () => {
  setStyle('insertUnorderedList');
  focusEditor();
};
 

์œ„์™€ ๊ฐ™์€ ์ฝ”๋“œ๋“ค์„ ๊ตฌ์„ฑ์„ ๋ณด๋ฉด ๋„ˆ๋ฌด ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง„๋‹ค๊ณ  ๋Š๊ปด์ง„๋‹ค. ๊ทธ๋ž˜์„œ ์ด ์ฝ”๋“œ๋ฅผ ์กฐ๊ธˆ ๋” ๊ฐ„์†Œํ™” ํ•  ์ˆ˜ ์žˆ์ง€ ์•Š์„๊นŒ ๊ณ ๋ฏผ ํ–ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋ฒ„ํŠผ์˜ value ๊ฐ’์œผ๋กœ ๊ฐ๊ธฐ ์Šคํƒ€์ผ ์ด๋ฆ„์œผ๋กœ ์ •์˜ํ•˜๊ณ  ์ด๋ฅผ ์ด๋ฒคํŠธ๋กœ ์ฒ˜๋ฆฌํ•จ์œผ๋กœ value๊ฐ’์„ ๊ฐ€์ ธ์™€ setStyle์˜ execCommand ํ•จ์ˆ˜์— ์ „๋‹ฌํ•ด์ค€๋‹ค. ๊ทธ๋ ‡๊ฒŒ execCommand์—์„œ html ๋ฌธ์ž์—ด๋กœ ํ•ด๋‹น ํšจ๊ณผ๋“ค์„ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋œ๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ๋Š” ์œ„์˜ ๊ณ ์•ˆ์ ์„ ์ ์šฉํ•œ ์ฝ”๋“œ๋“ค์ด๋‹ค.

 
  const focusEditor = () => {
    editorRef.current.focus({ preventScroll: true });
  };
 
  function setStyle(style) {
    document.execCommand(style);
    focusEditor();
  }

  const handleToolClick = (e) => {
    const element = e.currentTarget.value;
    setStyle(element);
    focusEditor();
  }

  const handleImgToolClick = () => {
    // ํŒŒ์ผ ์„ ํƒ input์„ ํด๋ฆญํ•œ๋‹ค.
    imageSelectorRef.current.click();
  }

๊ทธ๋ ‡๋‹ค๋ฉด ์ด์ œ ๊ฐ ํ•จ์ˆ˜๋“ค์˜ ์—ญํ• ๋“ค์„ ์‚ดํŽด๋ณด์ž. ์•„๋ž˜ ์„ค๋ช…์—์„œ ์ž์„ธํ•œ ์ฝ”๋“œ๋Š” ๋”๋ณด๊ธฐ๋กœ ํ™•์ธํ•˜์ž.

* foucsEditor

๋”๋ณด๊ธฐ
  const focusEditor = () => {
    editorRef.current.focus({ preventScroll: true });
  };

์—ฌ๊ธฐ์„œ editorRef.current.focus({ preventScroll: true });๋Š” editorRef์˜ current ์†์„ฑ์„ ํ†ตํ•ด ์‹ค์ œ DOM ์š”์†Œ์— ์ ‘๊ทผํ•˜๊ณ  focus() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ•ด๋‹น DOM ์š”์†Œ์— ํฌ์ปค์Šค๋ฅผ ์„ค์ •ํ•œ๋‹ค. ์ด๋•Œ preventScroll: true ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ํฌ์ปค์Šค๋ฅผ ์„ค์ •ํ•  ๋•Œ ์Šคํฌ๋กค์„ ๋ฐฉ์ง€ํ•œ๋‹ค. ์ฆ‰, foucsEditor ํˆด์ด ์ ์šฉ๋˜์–ด ์žˆ๋Š” ํ•จ์ˆ˜๋“ค์€ editorRef๊ฐ€ ์ฐธ์กฐ ๋˜๊ณ  ์žˆ๋Š” contentEditable์„ ๋‚ดํฌํ•˜๊ณ  ์žˆ๋Š” divํƒœ๊ทธ์— ๋ชจ๋‘ ํฌ์ปค์Šค๊ฐ€ ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋”ฐ๋ผ์„œ ์œ„์˜ ๋ชจ๋“  ํ•จ์ˆ˜๋“ค์ด ๋™์ž‘ํ•˜๊ฒŒ ๋˜๋ฉด ํ•ด๋‹น div๋กœ ํฌ์ปค์Šค๊ฐ€ ์˜ฎ๊ฒจ ์ง„๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋” ๋‚˜์•„๊ฐ€ ์ด๊ฒƒ์ด ์ƒ์„ฑ๋˜๋Š” ๋‹จ๊ณ„๋ฅผ ๊ฑฐ์น˜๊ฒŒ ๋œ๋‹ค๋ฉด ๋ฐฐ์—ด๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰์ด ๋  ๊ฒƒ์ด๋‹ค.

* setStyle

๋”๋ณด๊ธฐ
  function setStyle(style) {
    document.execCommand(style);
    focusEditor();
  }

์ด ์ฝ”๋“œ๋Š” document.execCommand() ํ•จ์ˆ˜๋ฅผ์‚ฌ์šฉํ•˜์—ฌ ์ง€์ •๋œ ์Šคํƒ€์ผ์„ ์—๋””ํ„ฐ ์ปดํฌ๋„ŒํŠธ์— ์ ์šฉํžŒ๋‹ค. style ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ํ•ด๋‹น ์Šคํƒ€์ผ์˜ HTML๋ฌธ์ž์—ด ์‹๋ณ„์ž๋ฅผ ๋ฐ›๋Š”๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, 'bold', 'italic', 'underline' ๋“ฑ์˜ ์Šคํƒ€์ผ์ด ๋  ์ˆ˜ ์žˆ๋‹ค. document.execCommand() ๋ฉ”์„œ๋“œ๋Š” ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ํŽธ์ง‘ ๋™์ž‘์„ ์‹คํ–‰์‹œํ‚ค๋Š” ํ•จ์ˆ˜๋กœ ์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž๊ฐ€ ์—ฌ๋Ÿฌ ์Šคํƒ€์ผ๋“ค์„ ๋ณ€๊ฒฝํ•˜๋Š” ๋“ฑ์˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹ค๋งŒ ์—ฌ๊ธฐ์„œ ๊ฑธ๋ฆฌ๋Š” ๊ฒƒ์ด ์žˆ๋‹ค๋ฉด execCommad()๋Š” ๊ณต์‹๋ฌธ์„œ MDN์—์„œ ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•˜์ง€ ์•Š๊ณ  ์žˆ๋‹ค. ํ˜„์žฌ ์ด ๋ถ€๋ถ„ ๋•Œ๋ฌธ์— ๊ณจ์น˜๊ฐ€ ์•„ํ”„์ง€๋งŒ ํ•ด๊ฒฐ ๋ฐฉ์•ˆ์ด ์ „ํ˜€ ์—†๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. execCommand์— ๊ด€ํ•ด์„œ๋Š” ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋”ฐ๋กœ ํฌ์ŠคํŒ…์„ ์˜ฌ๋ ค ๋†“๋„๋ก ํ•˜๊ฒ ๋‹ค.

* handleToolClick

๋”๋ณด๊ธฐ
  const handleToolClick = (e) => {
    const element = e.currentTarget.value;
    console.log(element);
    setStyle(element);
    focusEditor();
  }

 handleToolClick ํ•จ์ˆ˜๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ํŽธ์ง‘ ๋„๊ตฌ๋ฅผ ํด๋ฆญํ–ˆ์„ ๋•Œ ์‹คํ–‰๋˜๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์ด๋‹ค. ์•ž์„œ ์„ค๋ช…์„ ํ–ˆ์ง€๋งŒ ํ•ด๋‹น ๋ฒ„ํŠผ์„ ํด๋ฆญ์„ ํ–ˆ์„ ๋•Œ ํ•ด๋‹น ๋ฒ„ํŠผ์˜ value๊ฐ’์„ setStyle ํ•จ์ˆ˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋„˜๊ฒจ์ฃผ๋Š” ํ•จ์ˆ˜์ด๋‹ค. ์—ฌ๊ธฐ์„œ ์ฃผ๋ชฉํ•ด์•ผํ•  ๊ฒƒ์€ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•œ ๋ฐฉ์‹์ธ๋ฐ ๋ณดํ†ต e.target.value๋ฅผ ์‚ฌ์šฉํ•  ๋ฒ•ํ•˜์ง€๋งŒ ์ด ์ฝ”๋“œ์—์„œ๋Š” e.currentTarget.value๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. ๊ทธ ์ด์œ ๋Š” ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•œ ์š”์†Œ์™€ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์š”์†Œ๊ฐ€ ๋™์ผํ•œ ๊ฒฝ์šฐ์—๋Š” e.currentTarget๊ณผ e.target์ด ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” e.target์ด ์‹ค์ œ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•œ ์š”์†Œ๋ฅผ ์ฐธ์กฐํ•˜์ง€๋งŒ e.currentTarget์€ ํ•ญ์ƒ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์š”์†Œ๋กœ ์ฐธ์กฐํ•œ๋‹ค. ์ฆ‰, e.target์€ ํด๋ฆญ์ด๋‚˜ ๋งˆ์šฐ์Šค ์ด๋ฒคํŠธ์—์„œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ํด๋ฆญํ•œ ์š”์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋ฉฐ ์ž…๋ ฅ ํ•„๋“œ์—์„œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๊ฐ’์ด ์žˆ๋Š” ์š”์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค. e.currentTarget์€ ์ด๋ฒคํŠธ๋ฅผ ํ˜„์žฌ ์ฒ˜๋ฆฌ ์ค‘์ธ ์š”์†Œ, ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์‹ค์ œ๋กœ ์—ฐ๊ฒฐ๋œ ์š”์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ์ด๋‹ค. (์„ค๋ช…์ด ์กฐ๊ธˆ ๋ฏธํกํ•˜๋‹ค๊ณ  ์ƒ๊ฐ ๋œ๋‹ค.)
๋”ฐ๋ผ์„œ ์กฐ๊ธˆ ๋” ๋ช…์‹œ์ ์œผ๋กœ ๋ฒ„ํŠผ๋“ค์˜ value ๊ฐ’์„ ๊ตฌ๋ณ„ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— currentTarget์ด ๋งž๋‹ค๊ณ  ํŒ๋‹จ๋˜์–ด ์ด๋ ‡๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ฒŒ ๋œ๊ฒƒ์ด๋‹ค. ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง ๋ฌด์—‡์ธ์ง€ ์•Œ๊ณ  ์‹ถ์œผ๋ฉด ์•„๋ž˜ ๋”๋ณด๊ธฐ๋ฅผ ํ™•์ธํ•˜์ž.

๋”๋ณด๊ธฐ

## ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง ์ด๋ž€?

์ผ๋ฐ˜์ ์œผ๋กœ HTML ๋ฌธ์„œ์˜ ์š”์†Œ๋Š” ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค. ์ด๋•Œ ์ž์‹ ์š”์†Œ์—์„œ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ํ•ด๋‹น ์ด๋ฒคํŠธ๋Š” ์ž์‹ ์š”์†Œ์—์„œ ์ƒ์œ„๋กœ ์˜ฌ๋ผ๊ฐ€๋ฉฐ ๊ฐ ๋ถ€๋ชจ ์š”์†Œ๋กœ ์ „๋‹ฌ๋œ๋‹ค. ์ด๋Ÿฌํ•œ ์ด๋ฒคํŠธ ์ „ํŒŒ ๊ณผ์ •์„ ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง์ด๋ผ๊ณ  ํ•œ๋‹ค. ๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ๋ฅผ ๋“ค์–ด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ HTML ๊ตฌ์กฐ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž

<div id="parent">
    <div id="child">Click me!</div>
</div>


์ด๋•Œ #child ์š”์†Œ์— ํด๋ฆญ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ์ด๋ฒคํŠธ๋Š” #child์—์„œ ์‹œ์ž‘ํ•ด์„œ #parent๋กœ ์ „ํŒŒ๋œ๋‹ค. ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง์€ DOM ํŠธ๋ฆฌ์˜ ์ƒ์œ„ ์š”์†Œ๋กœ ์ด๋ฒคํŠธ๊ฐ€ ์ „ํŒŒ๋˜๋Š” ๊ณผ์ •์„ ์˜๋ฏธํ•œ๋‹ค. ์ฆ‰, ์ž์‹์•ˆ์—์„œ๋งŒ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ๋ฐœ์ƒ๋˜๊ฒŒ ํ•˜๊ณ  ์‹ถ์ง€๋งŒ ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง์ด ๋ฐœ์ƒํ•˜๊ฒŒ๋˜๋ฉด ๋ถ€๋ชจ๊นŒ์ง€ ํ—จ๋“ค๋ง ํ•˜๊ฒŒ ๋˜๋Š” ํ”ผ์น˜ ๋ชปํ•˜๋Š” ์ƒํ™ฉ๊นŒ์ง€ ๋„๋‹ฌ ํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

 

* handleImgToolClick

๋”๋ณด๊ธฐ
  const imageSelectorRef = useRef(null); // ํŒŒ์ผ ์„ ํƒ input ์š”์†Œ์— ๋Œ€ํ•œ ์ฐธ์กฐ
  ...
  const handleImgToolClick = () => {
    // ํŒŒ์ผ ์„ ํƒ input์„ ํด๋ฆญํ•œ๋‹ค.
    imageSelectorRef.current.click();
  }

handleImgToolClick ํ•จ์ˆ˜๋Š” ์ด๋ฏธ์ง€ ๋„๊ตฌ๋ฅผ ํด๋ฆญํ–ˆ์„ ๋•Œ ํŒŒ์ผ ์„ ํƒ input ์š”์†Œ๋ฅผ ํด๋ฆญํ•˜์—ฌ ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ฏธ์ง€๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ์—ญํ• ์„ ์ด๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ฏธ์ง€ ๋„๊ตฌ๋ฅผ ํด๋ฆญํ•˜๋ฉด ํŒŒ์ผ ์„ ํƒ input ์š”์†Œ๊ฐ€ ์ž๋™์œผ๋กœ ํด๋ฆญ๋˜์–ด ํŒŒ์ผ์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ์ฐฝ์ด ์—ด๋ฆฌ๊ฒŒ ๋œ๋‹ค. ๊ตฌ์ฒด์ ์œผ๋กœ ์กฐ๊ธˆ ๋” ์„ค๋ช… ํ•˜์ž๋ฉด imageSelectorRef.current.click()๋Š” imageSelectorRef๋ผ๋Š” Ref ๊ฐ์ฒด์˜ current ์†์„ฑ์„ ํ†ตํ•ด ํ˜„์žฌ DOM ๋…ธ๋“œ์— ์ ‘๊ทผํ•˜๊ณ  ๊ทธ DOM ๋…ธ๋“œ์˜ click() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. ์ด๋Š” ์‹ค์ œ๋กœ ํŒŒ์ผ ์„ ํƒ input ์š”์†Œ๋ฅผ ํด๋ฆญํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

์šฐ์„ ์—ฌ๊ธฐ ๊นŒ์ง€๊ฐ€ ๊ธฐ๋ณธ ํˆด๋ฐ”๋“ค์„ ์ œ์ž‘ํ•œ ๊ณผ์ •์ด๋‹ค. ๋‹ค์Œ ํฌ์ŠคํŒ…์—์„œ๋Š” ์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ถ€๋ถ„์„ ๋‹ค๋ฃจ์–ด ๋ณผ ๊ฒƒ์ด๋‹ค.

728x90
Comments