So i have some dummy data and want to filter through array and display objects that have that specific status.
Currently when i click on some checkbox it filters objects with clicked status correctly but then from what i understand - filtered data gets saved to invoiceList
state so unchecking it has zero sense, because next filtering is based on that filtered objects previously.
I also want to combine checked checkboxes so it filters objects with both e.g. "paid" and "pending" statutes.
How to do all of these filerings properly?
const {useState, useEffect} = React;
const DATA = [
{
name: "invoice1",
status: "paid"
},
{
name: "invoice2",
status: "paid"
},
{
name: "invoice3",
status: "pending"
},
{
name: "invoice4",
status: "draft"
}
];
const App = () => {
const [invoiceList, setInvoiceList] = useState([]);
useEffect(() => {
setInvoiceList(DATA);
}, []);
const statuses = ["draft", "pending", "paid"];
const [checkedState, setCheckedState] = useState(
new Array(statuses.length).fill(false)
);
const handleCheckboxChange = (position, status) => {
const updatedCheckedState = checkedState.map((item, index) =>
index === position ? !item : item
);
setCheckedState(updatedCheckedState);
//THIS
////////////////////////////////////////////
const filteredList = invoiceList.filter(
(invoice) => invoice.status === status
);
setInvoiceList(filteredList);
};
return (
<div>
<div>
{statuses.map((status, index) => (
<label key={index}>
<input
type="checkbox"
checked={checkedState[index]}
onChange={(e) => handleCheckboxChange(index, status)}
/>
<span>{status}</span>
</label>
))}
</div>
<ul>
{invoiceList.map((invoice,index) => {
return <li key={index}>{invoice.name}</li>;
})}
</ul>
</div>
);
}
const root = ReactDOM.createRoot(
document.getElementById("root")
).render(<App/>);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
CodePudding user response:
Instead of saving the state using setInvoiceList
, you may filter the list using useMemo
hook.
const {useState, useEffect, useMemo} = React;
const DATA = [
{
name: "invoice1",
status: "paid"
},
{
name: "invoice2",
status: "paid"
},
{
name: "invoice3",
status: "pending"
},
{
name: "invoice4",
status: "draft"
}
];
const App = () => {
const [invoiceList, setInvoiceList] = useState([]);
useEffect(() => {
setInvoiceList(DATA);
}, []);
const statuses = ["draft", "pending", "paid"];
// keep track of the selected/active status
const [activeStatus, setActiveStatus] = useState();
const filteredInvoices = useMemo(() => {
// if no active status, return all invoices
if (!activeStatus) {
return invoiceList;
}
// otherwise, filter invoices by active status
return invoiceList.filter(invoice => invoice.status === activeStatus);
},[activeStatus, invoiceList]);
return (
<div>
<div>
{statuses.map((status, index) => (
<label key={index}>
<input
type="checkbox"
checked={statuses[index] === activeStatus}
onChange={(e) => setActiveStatus(status === activeStatus ? undefined : status)}
/>
<span>{status}</span>
</label>
))}
</div>
<ul>
{filteredInvoices.map((invoice,index) => {
return <li key={index}>{invoice.name}</li>;
})}
</ul>
</div>
);
}
const root = ReactDOM.createRoot(
document.getElementById("root")
).render(<App/>);
For multiple status support, you can use the following
const {useState, useEffect, useMemo} = React;
const DATA = [
{
name: "invoice1",
status: "paid"
},
{
name: "invoice2",
status: "paid"
},
{
name: "invoice3",
status: "pending"
},
{
name: "invoice4",
status: "draft"
}
];
const App = () => {
const [invoiceList, setInvoiceList] = useState([]);
useEffect(() => {
setInvoiceList(DATA);
}, []);
const statuses = ["draft", "pending", "paid"];
// keep track of the selected/active statuses
const [activeStatuses, setActiveStatuses] = useState([]);
// toggle the status
const toggleStatus = (status) => {
if (activeStatuses.includes(status)) {
setActiveStatuses(activeStatuses.filter((s) => s !== status));
} else {
setActiveStatuses([...activeStatuses, status]);
}
};
// filter the invoices based on the active statuses
const filteredInvoices = useMemo(() => {
// if there are no active statuses, return the original list
if (activeStatuses.length === 0) {
return invoiceList;
}
// otherwise, filter the list
return invoiceList.filter(invoice => activeStatuses.includes(invoice.status));
},[activeStatuses, invoiceList]);
return (
<div>
<div>
{statuses.map((status, index) => (
<label key={index}>
<input
type="checkbox"
checked={activeStatuses.includes(status)}
onChange={(e) => toggleStatus(status)}
/>
<span>{status}</span>
</label>
))}
</div>
<ul>
{filteredInvoices.map((invoice,index) => {
return <li key={index}>{invoice.name}</li>;
})}
</ul>
</div>
);
}
const root = ReactDOM.createRoot(
document.getElementById("root")
).render(<App/>);