forward된 ref와 컴포넌트 자체 ref를 동시에 다루는 법

  • 자체 제작한 컴포넌트에 ref prop을 할당하기 위해서는 , forwardRef라는 기술을 사용해야 합니다.
  • forwardRef를 완료하였는데, 그 컴포넌트 자체에서도 ref를 다루어야할 경우 쓰는 테크닉입니다.
  • 컴포넌트 속에서 ref에 전달할 값을 콜백으로 설정하고, 그 콜백속에서 forward된 ref와 자체 ref를 동시에 할당하는 로직을 작성하면 됩니다.
  • 참고: 해당 버튼 컴포넌트는, 사내 마케터가 GTM 을 사용하여 사이트의 이벤트를 추적하기 위한 충분한 정보를 제공하고자 만들어졌습니다.
import { css } from '@emotion/react'
import { ButtonHTMLAttributes, forwardRef, useCallback, useEffect, useRef } from 'react'

const styles = {
  wrapper: css({
    '*': {
      pointerEvents: 'none',
    },
  }),
}

export type GAButtonProps = ButtonHTMLAttributes<HTMLButtonElement>

const GAButton = forwardRef<HTMLButtonElement, GAButtonProps>(
  ({ id, children, 'aria-label': ariaLabel, ...rest }: GAButtonProps, forwardedRef) => {
    const inRef = useRef<HTMLButtonElement | null>(null)

    const assignRef = useCallback(
      (node: HTMLButtonElement) => {
        if (forwardedRef) {
          if (typeof forwardedRef === 'function') {
            forwardedRef(node)
          } else {
            forwardedRef.current = node
          }
        }
        inRef.current = node
      },
      [forwardedRef]
    )

    useEffect(() => {
      const button = inRef.current

      if (button) {
        const slugifiedButtonText = (ariaLabel ?? button?.textContent ?? '')?.trim().replaceAll(' ', '-')

        if (!id) {
          button.setAttribute('id', `button--${slugifiedButtonText}`)
        }
        const textColor = window.getComputedStyle(button).color
        button.style.setProperty('--text-color', textColor)
      }
    }, [ariaLabel, children, id])

    return (
      <button ref={assignRef} id={id} aria-label={ariaLabel} css={styles.wrapper} {...rest}>
        {children}
      </button>
    )
  }
)

GAButton.displayName = 'GAButton'

export default GAButton