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.