How to prevent UUID from changing state when using copy-to-clipboard function?

Viewed 640

I managed to copy the generated UUID into my clipboard but whenever I click on the button, the UUID (and QR code) changes even though the page did not refresh. How to prevent the UUID from changing its state? Please refer to the codes below;

import React, { useState } from "react";
import Typography from "@material-ui/core/Typography";
import Button from "@material-ui/core/Button";
import FileCopyIcon from "@material-ui/icons/FileCopy";
import { v4 as uuid } from "uuid";
import QRCode from "react-qr-code";
import { CopyToClipboard } from "react-copy-to-clipboard";

export default function QRGenerator() {
  const adminId = uuid();

  const [qrcode, setQrcode] = useState({
    value: "",
    copied: false,
  });

  return (
    <div>
      <CopyToClipboard
        text={adminId}
        onCopy={() => setQrcode({ copied: true })}
      >
        <Button>
          <FileCopyIcon />
        </Button>
      </CopyToClipboard>

      <Typography align="center" variant="caption" paragraph="true">
        Admin ID : {adminId}
        {qrcode.copied ? <span style={{ color: "red" }}>Copied.</span> : null}
      </Typography>
      <QRCode value={adminId} />
    </div>
  );
}
2 Answers

Your code snippet has two issues.

First: adminId

React hook will be called multiple time within its lifecycle, and it will be given different value based on uuid()

To solve it, you can use useState or useRef or move it to outside QRGenerator function.

Second issue: updating state

setQrcode({ copied: true })} mean you will replace the value qrcode value with { copied: true} with value undefined

The below snippet will be the solution to the above issues

export default function QRGenerator() {
  const [adminId] = useState(uuid()); // or useRef(uuid());

  const [qrcode, setQrcode] = useState({
    value: "",
    copied: false,
  });

  return (
    <div>
      <CopyToClipboard
        text={adminId}
        onCopy={() => setQrcode({...qrcode, copied: true })} // this change only `copied` value
      >
        <Button>
          <FileCopyIcon />
        </Button>
      </CopyToClipboard>

      <Typography align="center" variant="caption" paragraph="true">
        Admin ID : {adminId}
        {qrcode.copied ? <span style={{ color: "red" }}>Copied.</span> : null}
      </Typography>
      <QRCode value={adminId} />
    </div>
  );
}

Hope this helps!

Every time the state is changed, render function is called. So the uuid is called again and it is changed. If you need the uuid to be constant, we can use useState

  const [adminId] = useState(uuid());

Or We have to pass it as prop from the parent component so that for every rerender it wont change.

Related