I am trying to filter my results via button onClicks in React, but for some reason its not working?
https://stackblitz.com/edit/react-x7tlxr?file=src/App.js
import React, {useEffect, useState} from "react";
import axios from 'axios';
import "./style.css";
export default function App() {
const [fetchData, setFetchData] = useState([]);
const [loading, setLoading] = useState(true);
const [isError, setIsError] = useState(false);
const url = 'https://jsonplaceholder.typicode.com/todos';
useEffect(() => {
let mounted = true;
const loadData = async () => {
try {
const response = await axios(url);
if (mounted) {
setFetchData(response.data);
setLoading(false);
setIsError(false);
console.log('data mounted')
}
} catch (err) {
setIsError(true)
setLoading(false);
setFetchData([]);
console.log(err);
}
};
loadData();
return () => {
mounted = false;
console.log('cleaned');
};
},
[url]
);
const renderdata = () => {
if (fetchData) {
return (
<div>{fetchData.map(inner => {
return (
<React.Fragment key={inner.id}>
<p>{inner.title}</p>
</React.Fragment>
)
})}</div>
)
} else {
<p>No data to display!</p>
}
}
const handle1 = () => {
const result1 = fetchData.filter((inner) => inner.id === '1');
setFetchData(result1);
}
const handle2 = () => {
const result2 = fetchData.filter((inner) => inner.id === '2');
setFetchData(result2);
}
const handleAll = () => {
setFetchData(fetchData);
}
return (
<div>
<button onClick={handleAll}>Show all</button>
<button onClick={handle1}>Filter by id 1</button>
<button onClick={handle2}>Filter by id 2</button>
{renderdata()}
</div>
);
}
CodePudding user response:
The id
is a number, not a string, so you filter(s) need to be changed like that:
const result1 = fetchData.filter((inner) => inner.id === 1);
You have another problem, is that you change the whole data set when you filter, so once you've filtered, you can't "unfilter" or filter again on another id.
You need to maintain the original fetchedData
unchanged.
This example shows how it can be fixed.
CodePudding user response:
I found 2 issues in your code
Id in the API result is numeric not string
inner.id === '2'
. so this will return falseinner.id === 2
you need to use like thiswhen you assign the filtered value to the original array it will of course change the original array so when you try to filter it second time you don't have the original API result in the fetch data array because it is already filtered So i have created one more array
filteredData
This will work.import React, {useEffect, useState} from "react"; import axios from 'axios'; import "./style.css"; export default function App() { const [fetchData, setFetchData] = useState([]); const [filteredData, setFileredData] = useState([]); const [loading, setLoading] = useState(true); const [isError, setIsError] = useState(false); const url = 'https://jsonplaceholder.typicode.com/todos'; useEffect(() => { let mounted = true; const loadData = async () => { try { const response = await axios(url); if (mounted) { setFetchData(response.data); setFileredData(response.data) setLoading(false); setIsError(false); console.log('data mounted') } } catch (err) { setIsError(true) setLoading(false); setFetchData([]); console.log(err); } }; loadData(); return () => { mounted = false; console.log('cleaned'); }; }, [url] ); const renderdata = () => { if (filteredData) { return ( <div>{filteredData.map(inner => { return ( <React.Fragment key={inner.id}> <p>{inner.title}</p> </React.Fragment> ) })}</div> ) } else { <p>No data to display!</p> } } const handle1 = () => { const result1 = fetchData.filter((inner) => inner.id === 1); setFileredData(result1); } const handle2 = () => { const result2 = fetchData.filter((inner) => inner.id === 2); setFileredData(result2); } const handleAll = () => { setFileredData(fetchData); } return ( <div> <button onClick={handleAll}>Show all</button> <button onClick={handle1}>Filter by id 1</button> <button onClick={handle2}>Filter by id 2</button> {renderdata()} </div> ); }