I can't seem to filter two separate things in react.js
I am able to filter by 'hotel ratings using state' but when I tried to add another, it wouldn't work. In the console it says should have a unique key prop.
How can I filter both data sets? currently i'm filtering one data set with
.filter((h) => filter.ratings.includes(h.hotel.starRating))
when I tried creating something similar like this
(filter((room) => extra.occupancy.includes(room.occupancy.maxAdults))
it breaks the code, why is that ?
This is my code:
import { useEffect, useState } from "react";
import './App.css';
export default function App() {
const [hotelRooms, setHotelRooms] = useState([]);
const [filter, setFilter] = useState({ ratings: ["1", "2", "3", "4", "5"] });
const [extra, setExtra] = useState ({occupancy: ["1", "2", "3", "4", "5"] });
const fetchHotels = async () => {
const res = await fetch(
"https://obmng.dbm.guestline.net/api/hotels?collection-id=OBMNG"
);
const hotels = await res.json();
const hotelRooms = [];
for (const hotel of hotels) {
const res = await fetch(
`https://obmng.dbm.guestline.net/api/roomRates/OBMNG/${hotel.id}`
);
const info = await res.json();
hotelRooms.push({ hotel, rooms: info.rooms });
}
setHotelRooms(hotelRooms);
};
useEffect(() => {
fetchHotels();
}, []);
const handleRatingFilter = (e) => {
if (e.target.checked) {
// adding value
const temp = [...filter.ratings];
temp.push(e.target.value);
setFilter({ ...filter, ratings: temp });
} else {
// removing value
setFilter({
...filter,
ratings: [...filter.ratings.filter((v) => v !== e.target.value)]
});
}
};
const handleOccupancyExtra = (e) => {
if (e.target.checked) {
const perm = [...extra.occupancy];
perm.push(e.target.value);
setExtra({...extra, occupancy: perm});
} else {
setExtra ({
...extra,
occupancy: [...extra.occupancy.filter((d) => d !== e.target.value)]
});
}
}
return (
<div className="App">
<div>
{["1", "2", "3", "4", "5"].map((star) => (
<div key={"input-" star}>
<input
id={"rated" star}
value={star}
name="ratings"
type="checkbox"
checked={filter.ratings.includes(star)}
onChange={handleRatingFilter}
/>
<label htmlFor={"rated" star}>Rated {star} star</label>
</div>
))}
</div>
<div>
{["1", "2", "3", "4", "5"].map((adults) => (
<div key={"adults" adults}>
<input
id={"maximum" adults}
value={adults}
name="extra"
type="checkbox"
checked={extra.occupancy.includes(adults)}
onChange={handleOccupancyExtra}
/>
<label htmlFor={"maximum" adults}>adults {adults}</label>
</div>
))}
</div>
{hotelRooms
.filter((h) => filter.ratings.includes(h.hotel.starRating))
.map((h) => (
<div>
<h2> Name: {h.hotel.name}</h2>
<p> Description: {h.hotel.description}</p>
<p> Rating: {h.hotel.starRating}</p>
<p> Postcode: {h.hotel.postcode}</p>
<p> City: {h.hotel.town}</p>
<p style={{ fontWeight: "bold" }}>Rooms:</p>
{
h.rooms.map((room) => (
<div>
<h5>Occupancy</h5>
<div> adults: {room.occupancy.maxAdults}</div>
<div> Children: {room.occupancy.maxChildren}</div>
<div> Maximum guests: {room.occupancy.maxOverall}</div>
<div> Room type: {room.name}</div>
</div>
))}
</div>
))}
</div>
);
}
CodePudding user response:
You can add multiple conditions inside filter.
Example:
const arr = [1,2,3,4,5,6,7,8,9,10]
const evenNums = arr.filter(num => num%2===0)
const biggerThan5 = arr.filter(num => num > 5)
const evenAndBiggerThan5 = arr.filter(num => num > 5 && num%2 === 0)
console.log("evenNums:", evenNums)
console.log("biggerThan5:", biggerThan5)
console.log("evenAndBiggerThan5:", evenAndBiggerThan5)
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
In your case
{hotelRooms
.filter((h) => filter.ratings.includes(h.hotel.starRating) && /* other condition (e.g. extra.occupancy.includes(...) */)
Codesandbox
This is a codesandbox based on my understanding of what you want to do.