javascriptreactjsregexundefined

I got this error in React - "Uncaught TypeError: Cannot read properties of undefined (reading 'match')" can someone help me please?


I'm creating a video game search app. I'm using an API so that clicking a searched game card takes you to a new page that contains images and a brief intro about the game. However, this does not work, as I get Uncaught TypeError: Cannot read properties of undefined (reading 'match') for my GameDetails component (at createParagraphs (GameDetails.jsx:8:33). It shows an error near a regex conversion where I try to convert the long text I get from API into 3 paragraph text. Searching online did not yield any answers, and I haven't found any syntax or regex errors.

The following is GameDetails.jsx:

import { useEffect, useState } from "react";
import useFetch from "../hooks/useFetch";
import { fetchGameData } from "../api";
import ScreenshotCarousel from "./ScreenshotCarousel";
import Spinner from "./Spinner";

function createParagraphs(inputString) {
  const sentences = inputString.match(/[^.!?]+[.!?]+/g) || [];

  const paragraphs = [];

  for (let i = 0; i < sentences.length; i += 3) {
    const paragraph = sentences
      .slice(i, i + 3)
      .join(" ")
      .trim();
    paragraphs.push(paragraph);
  }

  return paragraphs;
}

export default function GameDetails({ currentGame, goBack }) {
  const [description, setDescription] = useState([]);

  const { data, loading, fetchData, error, reset } = useFetch(() =>
    fetchGameData({ gameSlug: currentGame.slug })
  );

  useEffect(() => {
    (async () => {
      await fetchData();
    })();
  }, []);

  useEffect(() => {
    if (data) {
      const rawDescription = data.description_raw;
      const paragraphs = createParagraphs(rawDescription);

      setDescription(paragraphs);
    }
  }, [data]);

  return (
    <section>
      <button className="main-button flex" onClick={goBack}>
        <img src="./back-arrow.svg" /> <span className="mx-2">Go Back</span>
      </button>

      {loading ? (
        <div className="flex justify-center mt-4">
          <Spinner />
        </div>
      ) : (
        <div className="mt-4">
          <div className="w-full relative">
            <div className="absolute inset-0 bg-gradient-to-b from-black via-transparent to-transparent opacity-80"></div>
            <h1 className="text-gray-200 text-2xl absolute top-5 left-5">
              {currentGame.name}
            </h1>
            <img
              className="w-full h-40 object-cover rounded-md"
              src={currentGame.background_image}
            />
          </div>
          <div className="">
            {data && (
              <div className="text-gray-300">
                {description.map((paragraph, index) => (
                  <p className="mt-2" key={index}>
                    {paragraph}
                  </p>
                ))}
              </div>
            )}

            <div className="w-full flex flex-col items-center p-4 h-96">
              {currentGame.short_screenshots.length !== 0 && (
                <ScreenshotCarousel
                  screenshots={currentGame.short_screenshots.slice(0)} 
                />
              )}
            </div>

            <div className="grid grid-cols-2 py-4">
              <div className="flex flex-col">
                <h2 className="text-gray-300 text-xl">Genres</h2>
                <ul className="flex flex-wrap gap-2 py-2">
                  {currentGame.genres.map((genre) => (
                    <li className="genre-pill" key={genre.name}>
                      {genre.name}
                    </li>
                  ))}
                </ul>
                <h2 className="text-gray-300 text-xl">Platforms</h2>
                <ul className="flex flex-wrap gap-2 py-2">
                  {currentGame.platforms.map((platform) => (
                    <li key={platform.platform.name} className="platform-pill">
                      {platform.platform.name}
                    </li>
                  ))}
                </ul>
              </div>
              <div className="flex justify-center items-center">
                <button
                  className="main-button flex items-center"
                  onClick={() =>
                    window.open(
                      `https://google.com/search?q=where+to+buy+${currentGame.name}`,
                      "_blank"
                    )
                  }
                >
                  <span className="ml-4 mr-2">Purchase</span>
                  <img src="./shopping-cart.svg" className="size-6 mr-4" />
                </button>
              </div>
            </div>
          </div>
        </div>
      )}
    </section>
  );
}

Solution

  • You just need to safely handle undefined or empty strings in createParagraphs:

    function createParagraphs(inputString) {
      if (!inputString) return []; 
    
      const sentences = inputString.match(/[^.!?]+[.!?]+/g) || [];
    
      const paragraphs = [];
    
      for (let i = 0; i < sentences.length; i += 3) {
        const paragraph = sentences
          .slice(i, i + 3)
          .join(" ")
          .trim();
        paragraphs.push(paragraph);
      }
    
      return paragraphs;
    }
    

    Some game descriptions might not have punctuation at all. In that case, .match(/[^.!?]+[.!?]+/g) returns null, which you already handle with || []. But adding the if (!inputString) check ensures your component won’t crash even if description_raw is missing.