I'm trying to handle copy to clipboard in React with useRef hook. How can I achieve it without any additional libraries? Here is my code but it throws an error "myRef.current.select is not a function".
import React, { useRef } from "react";
const Element = () => {
const myRef = useRef();
const copyToClipboard = () => {
myRef.current.select();
document.execCommand("copy");
};
return (
<div>
<span onClick={copyToClipboard} ref={myRef}>
Text to be copied
</span>
</div>
);
};
export default Element;
Run the following snippet(s).
CopyToClipElement
component (with React Hooks) which handles the copy for given text prop. Use this component in your render. const CopyToClipElement = ({ text }) => { const myRef = React.useRef(null); const [data, setData] = React.useState(text); React.useEffect(() => setData(text), [text]); React.useEffect(() => { if (myRef.current && data) { myRef.current.select(); document.execCommand("copy"); setData(null); } }, [data, myRef.current]); return <div>{data && <textarea ref={myRef}>{data}</textarea>}</div>; }; const Element = () => { const [copyText, setCopyText] = React.useState(""); const data = ["Text to be copied", "Copy foo"]; return ( <div> {data.map((text) => ( <span style={{ margin: "10px", cursor: "pointer", color: 'blue' }} onClick={() => setCopyText(text)} > {text} </span> ))} <CopyToClipElement text={copyText} /> </div> ); }; const domContainer = document.querySelector('#app'); ReactDOM.render(<Element/>, domContainer);
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script> <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script> <div id="app"> </div>
copyToClipboard
in plain JS. const copyToClipboard = (text: string) => { const ta = document.createElement("textarea"); ta.innerText = text; document.body.appendChild(ta); ta.select(); document.execCommand("copy"); ta.remove(); }; const Element = () => { const data = ["Text to be copied", "Copy Bar"]; return ( <div> {data.map((text) => ( <span style={{ margin: "10px", cursor: "pointer", color: 'red' }} onClick={() => copyToClipboard(text)} > {text} </span> ))} </div> ); }; const domContainer = document.querySelector('#app'); ReactDOM.render(<Element />, domContainer);
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script> <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script> <div id="app"> </div>
Take a look at this solution , I just adapted it to your use case.
const copyToClipboard = () => {
const range = document.createRange();
range.selectNode(myRef.current);
window.getSelection().addRange(range);
try {
// Now that we've selected the anchor text, execute the copy command
const successful = document.execCommand('copy');
const msg = successful ? 'successful' : 'unsuccessful';
console.log('Copy email command was ' + msg);
} catch(err) {
console.log('Oops, unable to copy');
}
// Remove the selections - NOTE: Should use
// removeRange(range) when it is supported
window.getSelection().removeAllRanges();
};
Ciao, I found a solution but I had to use input
instead of span
. And I haven't used useRef
hook but just a variable ( let myInput = null;
) and then on input ref I wrote ref={(ref) => myInput = ref}
. In this way, your copyToClipboard
works.
The code:
function App() {
let myInput = null;
const copyToClipboard = () => {
myInput.select();
document.execCommand("copy");
alert("Copied the text: " + myInput.value);
};
return (
<div>
<input readOnly value="Text to copy" onClick={copyToClipboard} ref={(ref) => myInput = ref} />
</div>
);
}
Here the codesandbox example.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.