React Strict mode is missing letters in my Next.JS typed text carousel component

31 Views Asked by At

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>
  );
}
0

There are 0 best solutions below