skip to Main Content

I seem to be getting the error "filtered.map is not a function" and I’m assuming its because of my onSnapshot returning a null because it hasn’t fired yet to pull the data, (aka make it available) to be used to filter inside my component.

If I change the .map from filtered useState to my useState knives then I can get the data and no error and when I change it back I can then use my filter component without any issues.

Parent Component:

function KnifesComponent() {
  const knifeCollection = collection(db, "knives");
  const [knives, setKnives] = useState([]);
  const [count, setCount] = useState(0);

  const [filtered, setFiltered] = useState([]);
  const [activeFilter, setActiveFilter] = useState("");

  useEffect(() => {
      const sub = onSnapshot(knifeCollection, (snapshot) => {
        setKnives(snapshot.docs.map((doc) => ({ ...doc.data(), id: doc.id })));
        setFiltered(snapshot.docs.map((doc) => ({ ...doc.data(), id: doc.id })));
        const TotalSkins = snapshot.size;
        setCount(TotalSkins);
      });
      return () => {
        sub();
      }
  }, []);

  const rarities = {
    Exclusive: "Rarity_Exclusive.png",
    Ultra: "Rarity_Ultra.png",
    Premium: "Rarity_Premium.png",
    Deluxe: "Rarity_Deluxe.png",
  };  

  return (
    <div className="collection">
      <h2 className="section-heading">
        Knives <div className="count">({count})</div>
        <Filter
          skins={knives}
          setFiltered={setFiltered}
          activeFilter={activeFilter}
          setActiveFilter={setActiveFilter}
        />
      </h2>
        {filtered.map((skin) => {
          return (
            <div
              layout
              animate={{ opacity: 1 }}
              initial={{ opacity: 0 }}
              exit={{ opacity: 0 }}
              className="skin-box"
              key={skin.id}
            >
              <div className="skin-rarity">
                <Image src={require(`../../public/${rarities[skin.rarity]}`)} />
              </div>
              <h4>{skin.name}</h4>
              <div className="skin-value">
                <p>{skin.value}</p>
              </div>
            </div>
          );
        })}
      <div className="clearfix"></div>
    </div>
  );
}

Filter Component:

function Filter({ setActiveFilter, activeFilter, setFiltered, skins }) {
  useEffect(() => {
    if (activeFilter === "") {
      setFiltered("");
      return;
    }
    const filtered = skins.filter((skin) => skin.rarity.includes(activeFilter));
    console.log(filtered)
    setFiltered(filtered);
  }, [activeFilter]);

  return (
    <div className="filter-container">
      <button
        className={activeFilter === [] ? "active" : ""}
        onClick={() => setActiveFilter([])}
      >
        All
      </button>
      <button
        className={activeFilter === "Ultra" ? "active ultra" : "ultra"}
        onClick={() => setActiveFilter("Ultra")}
      >
        Ultra
      </button>
      <button
        className={
          activeFilter === "Exclusive" ? "active exclusive" : "exclusive"
        }
        onClick={() => setActiveFilter("Exclusive")}
      >
        Exclusive
      </button>
      <button
        className={activeFilter === "Premium" ? "active premium" : "premium"}
        onClick={() => setActiveFilter("Premium")}
      >
        Premium
      </button>
      <button
        className={activeFilter === "Deluxe" ? "active deluxe" : "deluxe"}
        onClick={() => setActiveFilter("Deluxe")}
      >
        Deluxe
      </button>
    </div>
  );
}

What am I doing wrong or what do I need to change to always have the array filled for the filter to work?

2

Answers


  1. Chosen as BEST ANSWER

    Mistake was fixed I failed to see I need to update my setFiltered to an array instead of a empty string

    if (activeFilter === "") {
      setFiltered("");
      return;
    }
    

    to

    if (activeFilter === "") {
      setFiltered([]);
      return;
    }
    

  2. This is one source of problems:

    if (activeFilter === "") {
      setFiltered("");
      return;
    }
    

    You’re setting the filtered state variable to an empty string, but all other code (including when you declare filtered in useState assumes that it is an array.

    My guess is that you want to do:

    if (activeFilter === "") {
      setFiltered([]);
      return;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search