Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Uncaught Error: Rendered fewer hooks than expected

This component with map method is giving me an error that says Rendered fewer hooks than expected, only when I am filtering, i don’t quite get, any help would much appreciated.

I know usually, The error "Rendered fewer hooks than expected" in a React component typically occurs when the order of hooks or the number of hooks called varies between renders. In my code, the filtering the event is based on the country value and nothing else.

 useEffect(() => {
    setfilteredEvents(
      events.filter((event) => event.country === selectedCountry)
    );

  }, [country]);

even when i do something like this manually is still causing the problem

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

 useEffect(() => {
        setfilteredEvents(
          events.filter((event) => event.country === "France")
        );
 
      }, [country]);

Here is the full code

import { useEffect, useState } from "react";
import SecHeading from "../../../GlobalUI/SecHeading";
import EventsType from "../../../Types/EventsType";
import ExpandedSearch from "./ExpandedSearch";
import TriggerSearch from "./TriggerSearch";
import eventStore from "../../../Store/eventStore";
import { events } from "../../../Data/eventsData";

export default function EventsList({ expanded, setExpanded }: EventsListProps) {
  const { country } = eventStore();
  const selectedCountry = country;
  const [filteredEvents, setfilteredEvents] = useState(events);

  useEffect(() => {
    setfilteredEvents(
      events.filter((event) => event.country === selectedCountry)
    );
    // console.log(filteredEvents);
  }, [country]);

  return (
    <div>
      <div
        className={
          expanded
            ? "mt-6  mb-2 open-searchbar "
            : "mt-6  mb-2 closed-searchbar"
        }
      >
        {expanded && <ExpandedSearch setExpanded={setExpanded} />}
      </div>
      <TriggerSearch expanded={expanded} setExpanded={setExpanded} />
      <div className="grid grid-cols-1 sm:grid-cols-2  justify-between sm:max-w-[90vw]">
        {filteredEvents.map((event: EventsType) => {
          const [imageLoaded, setImageLoaded] = useState(false);
          const onLoad = () => {
            setImageLoaded(true);
          };

          return (
            <div
              key={event.id}
              className="border border-1 border-black p-2 m-4  cursor-pointer rounded-lg max-w-[500px] "
            >
              <div className="relative max-h-[500px]">
                <img
                  src={event.photos[0]}
                  alt=""
                  className="hidden"
                  onLoad={onLoad}
                />
                {imageLoaded ? (
                  <img
                    src={event.photos[0]}
                    alt=""
                    className="h-[250px] lg:h-[300px] w-full object-cover"
                  />
                ) : (
                  <div className="h-[250px] lg:h-[300px] animate-pulse w-full bg-gray-100"></div>
                )}
              </div>

              <div className="p-2 flex flex-col gap-2">
                <SecHeading css="">{event.title}</SecHeading>
                <p className="truncate max-w-[90%] text-gray-600">
                  {event.description}
                </p>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

type EventsListProps = {
  expanded: boolean;
  setExpanded: CustomDispatch<boolean>;
};

>Solution :

React tracks state across function component renders, so when you conditionally use a hook (like useState) it causes problems for react. "Conditionally", in your case, means that across renders it will likely be rendered a different number of times.

Instead of doing this nested in the parent component, create a child component as shown below.

The reason this works is that the child component result is memoized and not re-evaluated. In your code, useState is called an additional time for each item for each render.


import { useEffect, useState } from "react";
import SecHeading from "../../../GlobalUI/SecHeading";
import EventsType from "../../../Types/EventsType";
import ExpandedSearch from "./ExpandedSearch";
import TriggerSearch from "./TriggerSearch";
import eventStore from "../../../Store/eventStore";
import { events } from "../../../Data/eventsData";

const EventItem = ({event}: { event: EventsType }) => {
  const [imageLoaded, setImageLoaded] = useState(false);
  const onLoad = () => {
    setImageLoaded(true);
  };

  return (
    <div
      key={event.id}
      className="border border-1 border-black p-2 m-4  cursor-pointer rounded-lg max-w-[500px] "
    >
      <div className="relative max-h-[500px]">
        <img
          src={event.photos[0]}
          alt=""
          className="hidden"
          onLoad={onLoad}
        />
        {imageLoaded ? (
          <img
            src={event.photos[0]}
            alt=""
            className="h-[250px] lg:h-[300px] w-full object-cover"
          />
        ) : (
          <div className="h-[250px] lg:h-[300px] animate-pulse w-full bg-gray-100"></div>
        )}
      </div>

      <div className="p-2 flex flex-col gap-2">
        <SecHeading css="">{event.title}</SecHeading>
        <p className="truncate max-w-[90%] text-gray-600">
          {event.description}
        </p>
      </div>
    </div>
  );
};

export default function EventsList({ expanded, setExpanded }: EventsListProps) {
  const { country } = eventStore();
  const selectedCountry = country;
  const [filteredEvents, setfilteredEvents] = useState(events);

  useEffect(() => {
    setfilteredEvents(
      events.filter((event) => event.country === selectedCountry)
    );
    // console.log(filteredEvents);
  }, [country]);

  return (
    <div>
      <div
        className={
          expanded
            ? "mt-6  mb-2 open-searchbar "
            : "mt-6  mb-2 closed-searchbar"
        }
      >
        {expanded && <ExpandedSearch setExpanded={setExpanded} />}
      </div>
      <TriggerSearch expanded={expanded} setExpanded={setExpanded} />
      <div className="grid grid-cols-1 sm:grid-cols-2  justify-between sm:max-w-[90vw]">
        {filteredEvents.map((event: EventsType) => <EventItem event={event}/>) }
      </div>
    </div>
  );
}



type EventsListProps = {
  expanded: boolean;
  setExpanded: CustomDispatch<boolean>;
};
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading