简体   繁体   中英

How to change opacity with clickEvent in React?

I'm trying to change opacity of the span below so that I can show the user that the text is copied.

before copyToClipboard clicked => opacity: 0 after clicked => opacity: 1 for about 1 sec and again to opacity:0

I know onCopy={timer} wouldn't work but I really can't figure out how to approach.

import React, { useState, useEffect } from "react"
import { CopyToClipboard } from "react-copy-to-clipboard"

const Contact = () => {
  const [style, setStyle] = useState({ opacity: 0 })

  useEffect(() => {
    const timer = setTimeout(function () {
      setStyle({ opacity: 1 })
    }, 1000)
  }, [])

  return (
        <div>
          <CopyToClipboard text='something' onCopy={timer}>
            <LogoImage />
          </CopyToClipboard>
          <span style={style}>
            copied!
          </span>
        </div>

I think you don't need useEffect for this case. Just create timer function outside useEffect like below:-

import React, { useState, useEffect } from "react"
import { CopyToClipboard } from "react-copy-to-clipboard"

const Contact = () => {
  const [style, setStyle] = useState({ opacity: 0 })

 const timer = () => {
    setStyle({ opacity: 1 });
    setTimeout(() => {
      setStyle({ opacity: 0 });
    }, 1000);
  };

  return (
        <div>
          <CopyToClipboard text='something' onCopy={() => timer()}>
            <LogoImage />
          </CopyToClipboard>
          <span style={style}>
            copied!
          </span>
        </div>
       )

I personally would not use timers for UI updates - ever. It does work (in this case), but it is not clean. I would suggest using CSS and a transition or animation. Removing/clearing the class name in onAnimationEnd makes sure the animation will trigger every time it is clicked. The animation duration is set to 1,4s out of which (0,2/1,4) = 14,29% are for fading in and 14,29% for fading out, that leaves 1s for the span to be shown

CSS:

.copied {
  opacity: 0;
  display:none;
}

.flash {
  display:inline-block;
  animation: flash 1.4s ease-in-out both;
}

@keyframes flash {
  0: {
    opacity: 0;
  }
  
  14.29% {
    opacity: 1;
  }
  
  85.71% {
    opacity: 1;
  }
  
  100% {
    opacity: 0
  }
}

(Simplified your example to remove the dependency on clipboard):

const Contact = () => {
  const [flash, setFlash] = React.useState("")

  const onClick = (event) => {
    setFlash("flash");
  }
  
  const onAnimationEnd = (event) => {
    setFlash("");
  }

  return (
        <div onClick={onClick}>
            Something
          <span className={`copied ${flash}`} onAnimationEnd={onAnimationEnd}>
            copied!
          </span>
        </div>
    )
}

Like in your example this has the downside that the element has to exist all the time (even though now with display:none removed from rendering).

An even better approach would be to use the amazing TransitionGroup/CSSTransition from react-transition-group to add/remove the element. Admittedly, a bit much for this example, but in general the better and cleaner way to go.

Instead of using setTimeout,you can use simple CSS animations to achieve the following -

  1. Create a CSS animation using keyframes
  2. Create a state to cause the animation and change state onCopy. And that's it.

Check the code here, for ref- https://codesandbox.io/s/festive-northcutt-kb32u?file=/src/App.js

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