I have a react component that receives an array of strings (facts).
The component cycles through the array and displays each fact individually.
Each fact is presented letter by letter as though being actively type and once the string is completely visible the timer waits 2 seconds before passing to the new string.
The text is accompanied by a flashing cursor ("|" symbol).
The component works perfectly until I engage reactStrictMode
const nextConfig = {
// reactStrictMode destroys the carousel
reactStrictMode: true,
compiler: {
styledComponents: true,
},
Then the letters become garbled as the app doesn't progress through the string correctly. (I assume reactStrictMode because it renders twice which means it misses rendering the second letter because it requires a second load. for example.
"More than 68 thousand lines of surviving code make up this portfolio."
becomes
"Meta 8tosn ie fsriigcd aeu hsprflo"
lots of missing letters.
"M--e t-a- -8 t-o-s-n- -i-e- -f s-r-i-i-g c-d- -a-e u- -h-s p-r-f-l-o"
Does anyone know of a solution to this or how I might look it up. Not many entries on strictmode missing letters in my string (ha-ha). I can just turn off strict mode but I need to use SSR and all the documentation recommends I use it.
Here is the code for my component
import { styled } from "styled-components";
import { useEffect, useState } from "react";
export default function FactCarousel({ facts }) {
// State variables for managing the displayed fact, current fact index, and cursor visibility
const [currentFactIndex, setCurrentFactIndex] = useState(0);
const [displayedFact, setDisplayedFact] = useState("");
const [showCursor, setShowCursor] = useState(true);
// useEffect hook to handle the typing effect and cursor blinking
useEffect(() => {
let interval;
// Function to simulate typing effect for a given fact
const typeFact = (fact) => {
let currentCharIndex = 0;
interval = setInterval(() => {
setDisplayedFact((prevDisplayedFact) => {
if (currentCharIndex >= fact.length) {
clearInterval(interval);
// After typing, wait x before moving to the next fact
setTimeout(() => {
setCurrentFactIndex(
(prevIndex) => (prevIndex + 1) % facts.length
);
setDisplayedFact("");
}, 2000); // 2000 milliseconds = 2 seconds .
return prevDisplayedFact;
}
return prevDisplayedFact + fact.charAt(currentCharIndex++);
});
}, 50); // Adjust typing speed by changing the interval value (milliseconds).
};
// Initial typing for the first fact
typeFact(facts[currentFactIndex]);
// Interval for controlling the blinking rate of the cursor
const cursorInterval = setInterval(() => {
setShowCursor((prevShowCursor) => !prevShowCursor);
}, 500); // 500 milliseconds = 0.5 seconds I.E. 1 on/off cycle per second.
// Cleanup function to clear intervals when the component unmounts
return () => {
clearInterval(interval);
clearInterval(cursorInterval);
};
}, [facts, currentFactIndex]);
return (
<div>
<p>
{displayedFact}
<span style={{ opacity: showCursor ? 1 : 0 }}>|</span>
</p>
</div>
);
}