Home > Software design >  Struggling to filter by category properly
Struggling to filter by category properly

Time:11-15

import React, { useEffect, useState } from "react";
import Loading from "./Loading";

function App() {
    const url = "https://course-api.com/react-tabs-project";
    const [loading, setLoading] = useState(true);
    const [data, setData] = useState([]);
    
    async function setCompany(companyName) {
        await getData();
        const newData = data.filter((info) => info.company === companyName);
        setData(newData);
    }

    async function getData() {
        try {
            const response = await fetch(url);
            const data = await response.json();
            setData(data);
            setLoading(false);
        } catch (err) {
            setLoading(false);
            console.error(`ERROR  ==> ${err}`);
        }
    }

    useEffect(() => {
        getData();
    }, []);

    if (loading) {
        return <Loading></Loading>; // simple loading screen
    }
    return (
        <main>
            <div className="top-wrapper">
                <h2>Experience</h2>
                <div className="underline"></div>
            </div>
            {data.map((item) => {
                const { id, order, title, dates, duties, company } = item;
                return (
                    <article key={id}>
                        <h3>{title}</h3>
                        <span className="company">{company}</span>
                        <p>{dates}</p>
                        <ul>
                            {duties.map((duty, index) => {
                                return <li key={index}>{duty}</li>;
                            })}
                        </ul>
                        <button>MORE INFO</button>
                    </article>
                );
            })}
            <div className="nav-buttons">
                <button
                    onClick={() => {
                        setCompany("TOMMY");
                    }}
                    className="nav-btn"
                >
                    TOMMY
                </button>
                <button
                    onClick={() => {
                        setCompany("BIGDROP");
                    }}
                    className="nav-btn"
                >
                    BIGDROP
                </button>
                <button
                    onClick={() => {
                        setCompany("CUKER");
                    }}
                    className="nav-btn"
                >
                    CUKER
                </button>
            </div>
        </main>
    );
}

export default App;

Sooo... basically I'm trying to filter the array returned by Fetch and have it display only the category I want (I called it "company instead of category in my code") depending on which button I click as shown in the "nav-buttons" div down in the code. The first time I click on a button it works fine, but the second time it doesn't show anything as if it's filtering from an already filtered array which return no results obviously.

CodePudding user response:

update these two methods with these two lines:

async function setCompany(companyName) {
    const response=await getData(); //THIS ONE
    const newData = response.filter((info) => info.company === companyName);
    setData(newData);
}

async function getData() {
    try {
        const response = await fetch(url);
        const data = await response.json();
        setData(data);
        setLoading(false);
        return data;// And THIS ONE
    } catch (err) {
        setLoading(false);
        console.error(`ERROR  ==> ${err}`);
    }
}

CodePudding user response:

// Get the oportunity to learn about promises, and you will save so much time. ;)

import React, { useEffect, useState } from "react";

function App() {
    const url = "https://course-api.com/react-tabs-project";
    const [loading, setLoading] = useState(true);
    const [data, setData] = useState([]);
    const [companyName, setCompanyName] = useState("");

    async function setCompany(companyName) {
        getData();
        const newData = setData(newData);
    }

    function getData(companyName) {
        setCompanyName(companyName);

        fetch(url)
            .then((res) => res.json())
            .then((info) => {
                console.log(info);
                return companyName
                    ? info.filter((info) => info.company == companyName)
                    : info;
            })
            .then((res) => {
                console.log(res);
                return setData(res);
            })
            .catch((err) => {
                setLoading(false);
                console.error(`ERROR  ==> ${err}`);
            });
    }

    useEffect(() => {
        getData();
    }, []);

    return (
        <main>
            <div className="top-wrapper">
                <h2>Experience</h2>
                <div className="underline"></div>
            </div>
            {data.map((item) => {
                const { id, order, title, dates, duties, company } = item;
                return (
                    <article key={id}>
                        <h3>{title}</h3>
                        <span className="company">{company}</span>
                        <p>{dates}</p>
                        <ul>
                            {duties.map((duty, index) => {
                                return <li key={index}>{duty}</li>;
                            })}
                        </ul>
                        <button>MORE INFO</button>
                    </article>
                );
            })}
            <div className="nav-buttons">
                <button
                    onClick={() => getData("TOMMY")}
                    className="nav-btn"
                >
                    TOMMY
                </button>
                <button
                    onClick={() => getData("BIGDROP")}
                    className="nav-btn"
                >
                    BIGDROP
                </button>
                <button
                    onClick={() => getData("CUKER")}
                    className="nav-btn"
                >
                    CUKER
                </button>
            </div>
        </main>
    );
}

export default App;

CodePudding user response:

  • you don't need to call the same API on each filter as it returns same data if I'm not wrong.
  • you can filter the data with the derived state, by storing the selected company in state i.e., on each render it calculates based on the selected company.
  • use the filtered data to render finally.

Here is the full e.g.

import React, { useEffect, useState } from "react";
import Loading from "./Loading";

function App() {
  const url = "https://course-api.com/react-tabs-project";
  const [loading, setLoading] = useState(true);
  const [data, setData] = useState([]);
  const [selectedCompany, setSelectedCompany] = useState("");  // store the company on click

  const filteredData = selectedCompany ? data.filter(info=> info.company === selectedCompany) : data;  // filter data based on selected company
  
  async function getData() {
    try {
      const response = await fetch(url);
      const data = await response.json();
      setData(data);
      setLoading(false);
    } catch (err) {
      setLoading(false);
      console.error(`ERROR  ==> ${err}`);
    }
  }

  useEffect(() => {
    getData();
  }, []);

  if (loading) {
    return <Loading></Loading>; // simple loading screen
  }
  return (
    <main>
      <div className="top-wrapper">
        <h2>Experience</h2>
        <div className="underline"></div>
      </div>
      {filteredData.map((item) => {
        const { id, order, title, dates, duties, company } = item;
        return (
          <article key={id}>
            <h3>{title}</h3>
            <span className="company">{company}</span>
            <p>{dates}</p>
            <ul>
              {duties.map((duty, index) => {
                return <li key={index}>{duty}</li>;
              })}
            </ul>
            <button>MORE INFO</button>
          </article>
        );
      })}
      <div className="nav-buttons">
        <button
          onClick={() => {
            setSelectedCompany("TOMMY");
          }}
          className="nav-btn"
        >
          TOMMY
        </button>
        <button
          onClick={() => {
            setSelectedCompany("BIGDROP");
          }}
          className="nav-btn"
        >
          BIGDROP
        </button>
        <button
          onClick={() => {
            setSelectedCompany("CUKER");
          }}
          className="nav-btn"
        >
          CUKER
        </button>
      </div>
    </main>
  );
}

export default App;

CodePudding user response:

try putting a check case before filter to insure that your array isn't empty.

 async function setCompany(companyName) {
        await getData();
        {data ? 
          const newData = data.filter((info) => info.company === companyName);
         :
        null}
        setData(newData);
    }

I think part of your issue is when your calling get data on button click your state isn't set before running the filter logic. I would look over your functional logic and ask yourself is this the best way to do this and am i trying to filter before or after my response.

  • Related