I have a simple React component that displays some text with a 'typewriter' kind of effect via CSS. The problem I have is that this typewriter effect is re-displayed every time the component re-renders but I only want it applied on the first render and never again. Is there a way to achieve this? Below is an example...
import React from 'react';
import './Typewriter.css'
export function Blah() {
return <div className='typewriter'>
My typewriter text here
</div>
}
.typewriter {
font-family: monospace;
color:#0000;
background:
linear-gradient(-90deg, #39ff14 5px,#0000 0) 10px 0,
linear-gradient(#39ff14 0 0) 0 0;
background-size:calc(100*1ch) 200%;
-webkit-background-clip:padding-box,text;
background-clip:padding-box,text;
background-repeat:no-repeat;
animation:
b .7s infinite steps(1),
t calc(100*.01s) steps(100) forwards;
}
@keyframes t{
from {background-size:0 200%}
}
@keyframes b{
50% {background-position:0 -100%,0 0}
}
CodePudding user response:
Stop the animation after the first time by using useRef
and useEffect
as in the following example
const { useRef, useEffect } = React;
const Example = () => {
const firstRender = useRef(true);
useEffect(() => {
firstRender.current = false;
}, []);
return <div className={firstRender.current ? 'typewriter' : ''}>
My typewriter text here
</div>
}
ReactDOM.render(<Example />, document.getElementById("react"));
.typewriter {
font-family: monospace;
color:#0000;
background:
linear-gradient(-90deg, #39ff14 5px,#0000 0) 10px 0,
linear-gradient(#39ff14 0 0) 0 0;
background-size:calc(100*1ch) 200%;
-webkit-background-clip:padding-box,text;
background-clip:padding-box,text;
background-repeat:no-repeat;
animation:
b .7s infinite steps(1),
t calc(100*.01s) steps(100) forwards;
}
@keyframes t{
from {background-size:0 200%}
}
@keyframes b{
50% {background-position:0 -100%,0 0}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
CodePudding user response:
I've created a sandbox for your component and I'm not seeing the effect you mentioned: https://codesandbox.io/s/react-playground-forked-w78bd2?file=/Blah.jsx
When you click the button it changes the text which re-renders the component (but does not re-mount it) and that does not cause the animation to happen again.
Perhaps you are re-mounting the component and the problem is further upstream in your app?