리액트로 클립보드 복사 기능 만들어보기 (feat. Custom Hook)
2021. 8. 16클립보드
클립보드는 개발자 뿐만 아니라 일반 웹 사용자들도 아주 잘 알고있는 용어일 것이다! 😲
특정 문구를 복사하고 싶은 욕구가 있을 때, 복사할 컨텐츠를 드래그 후 Ctrl + C 하는 방법도 있지만 그걸 더 편리하게 하기 위해 개발자들은 클립보드 복사 라는 버튼형태를 만들어 조금 더 유저에게 사용성이 높은 서비스를 제공하고 있다.
현재까지도 자주 사용되고 있고 실제로 많은 서비스에 적용이 되어있다.
예전부터 클립보드에 관련된 기능을 개발할 땐 document 객체에 있는 execCommand() 라는 함수를 통해 개발하였는데,
하지만 현재는..
보는 바와 같이 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
위 코드는 버튼을 클릭시 이벤트 핸들러가 동작하는 코드다.
이제 이걸 화면에서 눌러보면..
정상적으로 작동이 된다!
그리고 실제로 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를 통해 완료 여부를 알 수 있고, 그냥 만든 훅을 가져와서 사용만 하면 된다는 점이다.
자 그럼 결과는 어떻게 나올까?
아주 잘 동작한다! 🎉🎉🎉