简体   繁体   中英

React copy to clipboard using useRef hook

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).

  1. Have a separate 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>

  1. Alternatively, Just add the utility method 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM