리액트로 클립보드 복사 기능 만들어보기 (feat. Custom Hook)

2021. 8. 16

클립보드

클립보드는 개발자 뿐만 아니라 일반 웹 사용자들도 아주 잘 알고있는 용어일 것이다! 😲

특정 문구를 복사하고 싶은 욕구가 있을 때, 복사할 컨텐츠를 드래그 후 Ctrl + C 하는 방법도 있지만 그걸 더 편리하게 하기 위해 개발자들은 클립보드 복사 라는 버튼형태를 만들어 조금 더 유저에게 사용성이 높은 서비스를 제공하고 있다.

현재까지도 자주 사용되고 있고 실제로 많은 서비스에 적용이 되어있다.

예전부터 클립보드에 관련된 기능을 개발할 땐 document 객체에 있는 execCommand() 라는 함수를 통해 개발하였는데,

하지만 현재는..

deprecated

보는 바와 같이 Deprecated되어 현재 개발하는 기능에는 당연히 사용하지 말아야할 뿐더러 이전에 개발했던 기능들도 새롭게 대응을 해주어야 한다.. 😨

그러면 이를 대체할 새롭게 지원되는 API를 통해 만들어보자!

Clipboard API

이전에는 execCommand("copy")를 통해 개발하였다면, 현재는 정식으로 클립보드 API를 지원하는 전역 navigator 객체에서 clipboard API 를 바로 사용할 수 있다.

clipboard API의 메소드를 보게되면 writeText라는 메소드가 있는데, 요놈이 바로 클립보드 복사를 하기위한 친구다.

writeText 메소드는 Promise를 반환해주고 있으며, IE에서는 아예 지원이 안되고 있으니 꼭 인지해야한다. (악마 그 자체.. 😈)

이제 본격적으로 코드를 통해 복사 기능을 만들어보자

import React from 'react'
import './App.css'

function App() {
  const handleCopyClipBoard = async (text: string) => {
    try {
      await navigator.clipboard.writeText(text)

      alert('복사 성공!')
    } catch (error) {
      alert('복사 실패!')
    }
  }

  return (
    <div className="App">
      <button onClick={() => handleCopyClipBoard('복사된 텍스트')}>복사!!</button>
    </div>
  )
}

export default App

위 코드는 버튼을 클릭시 이벤트 핸들러가 동작하는 코드다.

이제 이걸 화면에서 눌러보면..

copy success

정상적으로 작동이 된다!

그리고 실제로 ctrl + v를 누르면 "복사된 텍스트" 라는 텍스트가 복사가 되어있다.

서론은 뭔가 굉장히 긴 느낌이었는데 금방 끝이 나버렸다.. 🤣

클립보드를 복사 했을 때 복사 성공 여부를 알고 싶다거나 혹은 클립보드 복사 기능이 여러군데서 사용될 여지가 있다면, 재활용을 감안한 커스텀 훅을 하나 만들어서 관리해야겠다는 생각이 문득 들었다.

그래서 일단 저 요구사항 2개를 가지고 커스텀 훅을 만들어보았다.

useCopyClipBoard

import { useState } from 'react'

type onCopyFn = (text: string) => Promise<boolean>

function useCopyClipBoard(): [boolean, onCopyFn] {
  const [isCopy, setIsCopy] = useState(false)

  const onCopy: onCopyFn = async (text: string) => {
    try {
      await navigator.clipboard.writeText(text)
      setIsCopy(true)

      return true
    } catch (error) {
      console.error(error)
      setIsCopy(false)

      return false
    }
  }

  return [isCopy, onCopy]
}

export default useCopyClipBoard

isCopy 상태를 통해 복사 여부를 알 수 있도록 만들었고, onCopy 이벤트를 통해 성공 및 실패에 대한 처리를 해주었다.

실제 사용되는 코드를 보자

import React from 'react'
import './App.css'

import useCopyClipBoard from './useCopyClipBoard'

function App() {
  const [isCopy, onCopy] = useCopyClipBoard()

  const handleCopyClipBoard = (text: string) => {
    onCopy(text)
  }

  return (
    <div className="App">
      <button onClick={() => handleCopyClipBoard('복사된 텍스트')}>복사!!</button>
      {isCopy && <span>복사 완료!!</span>}
    </div>
  )
}

export default App

아까와 크게 다른 부분은 isCopy를 통해 완료 여부를 알 수 있고, 그냥 만든 훅을 가져와서 사용만 하면 된다는 점이다.

자 그럼 결과는 어떻게 나올까?

copy success to hooks

아주 잘 동작한다! 🎉🎉🎉