[TECH-QA] React์—์„œ SVG ์•„์ด์ฝ˜ ๋‹ค๋ฃจ๊ธฐ: ์‹ค์šฉ์ ์ธ ์˜ˆ์ œ์™€ ํŒ

ref๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

React๋Š” ์„ ์–ธ์  UI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ, ์ผ๋ฐ˜์ ์œผ๋กœ ์ƒํƒœ์™€ props๋ฅผ ํ†ตํ•ด UI๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํŠน์ • ์ƒํ™ฉ์—์„œ๋Š” DOM ์š”์†Œ์— ์ง์ ‘ ์ ‘๊ทผํ•ด์•ผ ํ•  ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ref๋Š” ์ด๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋ฉฐ, ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์—์„œ ref๋ฅผ ์ƒ์„ฑํ•ด ์ž์‹ ์ปดํฌ๋„ŒํŠธ์— ์ „๋‹ฌํ•˜๋ฉด ์ž์‹์˜ DOM ์š”์†Œ(์—ฌ๊ธฐ์„œ๋Š” )๋ฅผ ๋ถ€๋ชจ์—์„œ ์กฐ์ž‘ํ•˜๊ฑฐ๋‚˜ ์ •๋ณด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ref๋ฅผ ํ†ตํ•ด ํ•  ์ˆ˜ ์žˆ๋Š” ์ž‘์—…

_Icon ์ปดํฌ๋„ŒํŠธ์˜ SVG ์š”์†Œ์— ref๋ฅผ ์ „๋‹ฌํ•˜์—ฌ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์ž‘์—…์˜ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

๐Ÿ“ DOM ์†์„ฑ/์ƒํƒœ ์กฐํšŒ

  • SVG ์š”์†Œ์˜ ํฌ๊ธฐ, ์œ„์น˜, ์†์„ฑ ๋“ฑ์„ ํ™•์ธ.
  • ์˜ˆ: ref.current.getBoundingClientRect()๋ฅผ ํ˜ธ์ถœํ•ด SVG์˜ ํ™”๋ฉด์ƒ ์œ„์น˜๋‚˜ ํฌ๊ธฐ๋ฅผ ํ™•์ธ.
  • ์šฉ๋„: ์• ๋‹ˆ๋ฉ”์ด์…˜์ด๋‚˜ ํˆดํŒ ์œ„์น˜ ๊ณ„์‚ฐ.

๐Ÿ“ ์ง์ ‘ DOM ์กฐ์ž‘

  • React ์ƒํƒœ ์™ธ๋ถ€์—์„œ SVG์˜ ์†์„ฑ์„ ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝ.
  • ์˜ˆ: ref.current.setAttribute('fill', 'red')๋กœ ์ƒ‰์ƒ์„ ๋ณ€๊ฒฝ.
  • ์šฉ๋„: React๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋ณต์žกํ•œ ๋™์  ์Šคํƒ€์ผ๋ง.

๐Ÿ“ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ œ์–ด

  • SVG ์š”์†Œ์— ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ ์šฉํ•˜๊ฑฐ๋‚˜ ์ œ์–ด.
  • ์˜ˆ: ref.current.animate()๋ฅผ ์‚ฌ์šฉํ•ด CSS/SVG ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ํŠธ๋ฆฌ๊ฑฐ.
  • ์šฉ๋„: ์•„์ด์ฝ˜์— ํด๋ฆญ ์‹œ ๊นœ๋นก์ด๋Š” ํšจ๊ณผ ์ถ”๊ฐ€.

๐Ÿ“ ํฌ์ปค์Šค ๊ด€๋ฆฌ

  • SVG ์š”์†Œ์— ํฌ์ปค์Šค๋ฅผ ์„ค์ •ํ•˜๊ฑฐ๋‚˜ ํ™•์ธ.
  • ์˜ˆ: ref.current.focus()๋กœ ์ ‘๊ทผ์„ฑ ๊ฐœ์„ .
  • ์šฉ๋„: ํ‚ค๋ณด๋“œ ๋‚ด๋น„๊ฒŒ์ด์…˜ ์ง€์›.

๐Ÿ“ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ํ†ตํ•ฉ

  • D3.js, GSAP ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ DOM ์š”์†Œ๋ฅผ ์ง์ ‘ ์กฐ์ž‘ํ•ด์•ผ ํ•  ๋•Œ.
  • ์˜ˆ: ref.current๋ฅผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์ „๋‹ฌํ•ด SVG ๊ฒฝ๋กœ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ ์šฉ.
  • ์šฉ๋„: ๋ณต์žกํ•œ ์‹œ๊ฐํ™” ์ž‘์—….

๐Ÿ“ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ

  • ํŠน์ • DOM ์ด๋ฒคํŠธ(์˜ˆ: ๋งˆ์šฐ์Šค ์˜ค๋ฒ„, ๋“œ๋ž˜๊ทธ)๋ฅผ ์ง์ ‘ ๊ฐ์ง€.
  • ์˜ˆ: ref.current.addEventListener('mouseover', handleMouseOver).
  • ์šฉ๋„: React์˜ ํ•ฉ์„ฑ ์ด๋ฒคํŠธ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์–ด๋ ค์šด ๊ฒฝ์šฐ.

๐Ÿ“ ์˜ˆ์ œ

import React, { useRef, useEffect } from 'react';
import { _ICon } from './IcArrowLeft';

const ParentComponent = () => {
  const svgRef = useRef(null);

  useEffect(() => {
    if (svgRef.current) {
      // SVG ์š”์†Œ์— ์ ‘๊ทผํ•˜์—ฌ ์ž‘์—… ์ˆ˜ํ–‰
      console.log('SVG ํฌ๊ธฐ:', svgRef.current.getBoundingClientRect());
      
      // ์˜ˆ: ์ƒ‰์ƒ ๋ณ€๊ฒฝ
      svgRef.current.setAttribute('fill', 'purple');
      
      // ์˜ˆ: ํด๋ฆญ ์ด๋ฒคํŠธ ์ถ”๊ฐ€
      svgRef.current.addEventListener('click', () => {
        alert('SVG ํด๋ฆญ๋จ!');
      });
    }
  }, []);

  return (
    <div>
      <_ICon
        ref={svgRef}
        size={32}
        color="blue"
        filled={true}
        aria-label="์™ผ์ชฝ ํ™”์‚ดํ‘œ"
      />
    </div>
  );
};

export default ParentComponent;
  • React ์ฒ ํ•™ ์ค€์ˆ˜: React๋Š” DOM ์ง์ ‘ ์กฐ์ž‘์„ ์ตœ์†Œํ™”ํ•˜๋„๋ก ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€๋Šฅํ•˜๋ฉด ์ƒํƒœ/props๋กœ UI๋ฅผ ๊ด€๋ฆฌํ•˜์„ธ์š”.
  • ์ ์ ˆํ•œ ์‚ฌ์šฉ: ref๋Š” ํฌ์ปค์Šค ๊ด€๋ฆฌ, ์• ๋‹ˆ๋ฉ”์ด์…˜, ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ†ตํ•ฉ ๋“ฑ ํ•„์ˆ˜์ ์ธ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•˜์„ธ์š”.
  • ์ ‘๊ทผ์„ฑ ๊ณ ๋ ค: SVG์— aria-label ๊ฐ™์€ ์†์„ฑ์„ ์ถ”๊ฐ€ํ•ด ์ ‘๊ทผ์„ฑ์„ ์œ ์ง€ํ•˜์„ธ์š”.
  • ref ์ „๋‹ฌ ๋ฐฉ์‹: _ICon React.forwardRef๋กœ ๋ž˜ํ•‘๋˜์–ด ์žˆ์–ด์•ผ ref๊ฐ€ SVG ์š”์†Œ์— ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค.