React Tips — Copy to Clipboard, Comparing Old and New Values with Hooks

John Au-Yeung - Oct 19 '20 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

React is a popular library for creating web apps and mobile apps.

In this article, we’ll look at some tips for writing better React apps.

How to Copy Text to Clipboard

We can copy text to the clipboard by using the navigator.ckipboard.writeText method.

For instance, we can write:

<button
  onClick={() => navigator.clipboard.writeText('copy this to clipboard')}
>
  copy to clipboard
</button>

Enter fullscreen mode Exit fullscreen mode

We copy the text in the string in the argument to the clipboard.

Also, we can use the react-copy-to-clipboard package to make our lives easier.

For instance, we can write:

import React from 'react';
import ReactDOM from 'react-dom';
import {CopyToClipboard} from 'react-copy-to-clipboard';

class App extends React.Component {
  state = {
    value: '',
    copied: false,
  };

  onChange({target: {value}}) {
    this.setState({value, copied: false});
  },

  render() {
    return (
      <div>
        <input value={this.state.value} onChange={this.onChange} />

        <CopyToClipboard text={this.state.value}
          onCopy={() => this.setState({copied: true})}>
          <span>Copy to clipboard with span</span>
        </CopyToClipboard>

      </div>
    );
  }
}

Enter fullscreen mode Exit fullscreen mode

The package comes with the CopyToClipboard component.

It takes the text prop with the text that we want to copy to the clipboard.

The onCopy prop is run when the text is copied.

Inside the component, we have the content that we can click to do the copying.

Once the element is clicked, the content in the text prop will be copied to the clipboard.

We can also use the execCommand method to copy the content of a DOM element that’s selected to the clipboard.

For instance, we can write:

import React, { useRef, useState } from 'react';

export default function CopyExample() {

const [copySuccess, setCopySuccess] = useState('');
  const textAreaRef = useRef(null);

  function copyToClipboard(e) {
    textAreaRef.current.select();
    document.execCommand('copy');
  };

  return (
    <div>
      {
       document.queryCommandSupported('copy') &&
        <div>
          <button onClick={copyToClipboard}>Copy</button>
          {copySuccess}
        </div>
      }
      <form>
        <textarea
          ref={textAreaRef}
          value='text to copy'
        />
      </form>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

We have a functional component with the copyToClipboard to select the text from our text area.

The selection is done by:

textAreaRef.current.select();

Enter fullscreen mode Exit fullscreen mode

textAreaRef is the ref that we assigned to the text area.

Then we call the execCommand with the 'copy' argument to copy the text that’s selected to the clipboard.

In the JSX we return, we check if the copy command is supported with:

document.queryCommandSupported('copy')

Enter fullscreen mode Exit fullscreen mode

and display a button to let us copy the data if it is.

We also have the text area that has the stuff to copy.

Identifying Different Inputs with One onChange Handler

We can use one event handler for multiple inputs.

To do that, we can create an event handler function that takes an argument to identify the input that we’ve changed.

For instance, we can write:

class App extends React.Component {
  constructor() {
    super();
    this.state = { input1: 0, input2: 0 };
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(input, value) {
    this.setState({
      [input]: value
    })
  }

  render() {
    return (
      <div>
        <input type="text" onChange={e => this.handleChange('input1', e.target.value)} />
        <input type="text" onChange={e => this.handleChange('input2', e.target.value)} />
      </div>
    )
  }
}

Enter fullscreen mode Exit fullscreen mode

We pass in a callback that calls the handleChange method with the key of the state that we want to change when the text is entered.

This way, we can change the input that we want.

setState in handleChange has a computed property name instead of a fixed property.

Compare Old Values and New Values with the useEffect Hook

We can use the useRef hook to get the previous value.

And we can get the latest values from the component itself.

For instance, we can write:

const usePrevious = (value) => {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}

const App = (props) => {
  const { amount, balance } = props
  const prevAmount = usePrevious({ amount, balance });
  useEffect(() => {
    if (prevAmount.amount !== amount) {
      //...
    }

    if (prevAmount.balance !== balance) {
      //...
    }
  }, [amount, balance])

  //...
}

Enter fullscreen mode Exit fullscreen mode

We created the usePrevious hook to get the previous values with useRef .

We set the old values to that we passed into the hook function by setting the values to the ref.current property.

The previous values are then returned from the hook.

In the App component, we get the latest values from the props.

And we get the old values from the usePrevious hook.

Then we can compare them in the useEffect callback.

The array that we passed in has the values that we want to watch for changes for.

Conclusion

We can set the previous values with the useRef hook.

There are various ways to copy text from a component to the clipboard.

We can identify different inputs in a component by creating our own event handler to identify them.

The post React Tips — Copy to Clipboard, Comparing Old and New Values with Hooks appeared first on The Web Dev.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .