How to reset React hook state with setTimeout in useEffect

Viewed 855

I have a simple component that copies a link to the clipboard, and would like to swap the link icon with a checkmark. I have the logic setup to do so, but having an issue getting the state reset after 3 seconds to reset the button back to the link icon. How can I properly setup my useEffect and state hook to set and then reset the state for showing/hiding the link to checkmark and back again?

const [copySuccess, setCopySuccess] = useState('');
const [visible, setVisible] = useState(true);
const copyToClipBoard = async copyHeader => {
try {
  await navigator.clipboard.writeText(copyHeader);
    setCopySuccess('Copied!');
  } catch (err) {
    setCopySuccess('Failed to copy!');
  }
};

<Button>
    {copySuccess ? (
       <Icon name="success" />
    ):(
     <Icon
        name="linked"
        onClick={() => copyToClipBoard(url)}
     />
    )}
</Button>

I was trying a useEffect like so:

useEffect(() => {
    setTimeout(() => {
      setVisible(false);
    }, 3000);
 });
  

but not sure how to use the setVisible state and timeout, to swap the icon back to the link to let users know they can copy it again.

2 Answers

You can derive the visible state from copySuccess state, try adding it to useEffect dep array:

const [copySuccess, setCopySuccess] = useState("");
const copyToClipBoard = async (copyHeader) => {
  try {
    await navigator.clipboard.writeText(copyHeader);
    setCopySuccess("Copied!");
  } catch (err) {
    setCopySuccess("Failed to copy!");
  }
};

useEffect(() => {
  if (copySuccess !== "") {
    setTimeout(() => {
      setCopySuccess("");
    }, 3000);
  }
}, [copySuccess]);

<Button>
  {copySuccess ? (
    <Icon name="success" />
  ) : (
    <Icon name="linked" onClick={() => copyToClipBoard(url)} />
  )}
</Button>;

See similar logic in codesandbox example:

function Component() {
  const [copyIsAvailable, setCopyIsAvailable] = useState(true);

  useEffect(() => {
    setTimeout(() => {
      setCopyIsAvailable(true);
    }, 1000);
  }, [copyIsAvailable]);

  return (
    <button onClick={() => setCopyIsAvailable(false)}>
      {copyIsAvailable ? "copy" : "copied"}
    </button>
  );
}

Edit Q-65373145-setTimeout

I could suggest you changing the async function to update visible.
Then change thee button tag:

<Button>
    {visible 
      ? <Icon name="success" />
      : <Icon
         name="linked"
         onClick={() => copyToClipBoard(url)}
        />
    }
</Button>
Related