posted: 2019/02/23
Clipboard.jsをReact Hooksで使うやつ
Clipboard.js、便利だけどこれもまたrefsを利用するので色々厄介だったがHooksでいい感じにできる。
React Clipboardなどは比較的安定している方ではありつつ、やっぱり自前でやれるならやれたほうが良い。(内部を見ると結構むちゃしているなーという感じはする)
あとcopiedでちょろっとアニメーションするようにしている
import React, { useRef, useLayoutEffect, useCallback, useState } from "react"
import { render } from "react-dom"
import Clipboard from "clipboard"
// targetを指定する時
const useClipboard = (onCopySuccess) => {
const buttonRef = useRef(null)
const targetRef = useRef(null)
useLayoutEffect(() => {
const cb = new Clipboard(buttonRef.current, {
target: () => targetRef.current
})
cb.on("success", (e) => {
onCopySuccess()
})
// cb.on("error", (e) => {
// })
return () => {
cb.destroy()
}
}, [])
return { buttonRef, targetRef }
}
export const CopyWithTarget = () => {
const [copyed, setCopied] = useState(false)
const onCopySuccess = useCallback(() => {
setCopied(true)
setTimeout(() => {
setCopied(false)
}, 1000)
}, [])
const { buttonRef, targetRef } = useClipboard(onCopySuccess)
return (
<div>
<textarea ref={targetRef} defaultValue={Math.random().toString()} />
<button ref={buttonRef}>Copy</button>
{copyed && <span>Copied!</span>}
</div>
)
}
// textを固定でコピーすれば良い時
const useClipboardText = (onCopySuccess) => {
const buttonRef = useRef(null)
useLayoutEffect(() => {
const cb = new Clipboard(buttonRef.current, {
text: () => "This is copied text"
})
cb.on("success", (e) => {
onCopySuccess()
})
cb.on("error", (e) => {
console.error(e)
})
return () => {
cb.destroy()
}
}, [])
return { buttonRef }
}
export const CopyWithText = () => {
const [copyed, setCopied] = useState(false)
const onCopySuccess = useCallback(() => {
setCopied(true)
setTimeout(() => {
setCopied(false)
}, 1000)
}, [])
const { buttonRef } = useClipboardText(onCopySuccess)
return (
<div>
<span>Copy text</span>
<button ref={buttonRef}>Copy</button>
{copyed && <span>Copied!</span>}
</div>
)
}