首页 > 解决方案 > How can I filter through what is displayed with useEffect?

问题描述

I am a bit lost on what to do for the next step. I have managed to display the content but I can't seem to get it to filter with a click. It was easy enough to do with a different api , i followed webdevsimplified but this i can't work out and I am at my wits end!

All I want is to filter through the mapped api. for example if I check 3, it should show me only 3 starRating. Can anybody offer me some advice please.

App.js

import { useEffect, useState, useRef } from 'react'
import Header from './components/Header';
import SearchBar from './components/SearchBar';



export default function App() {
  const [hotelRooms, setHotelRooms] = useState([]);

 
 
  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()
    
    
  }, [])

 
 
  
  return (
    <div className="App">
      
      <Header/>
     
      {
        hotelRooms.map(h => (
          
          <div>

          <input value={"1"} type="checkbox" onChange={}/>
          <input value={"Adults"}type="checkbox" onChange={}/>
          
          
            <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>
            <img src={h.hotel.images}/>
            
                               

            <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>
                <img src={room.images}/>
               </div>
             ))
            }
          </div>
        ))
      }
    </div>
  );
}

标签: reactjsapiuse-effect

解决方案


You should have a state that saves the filtered properties.

const [filter, setFilter] = useState({ ratings: ["1", "2", "3", "4", "5"] });

When you show the checkboxes add a name to them and the respective values. Remember when you use .map in render, add an unique key to the out most tag.

<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>

Now in the onChange handler, update the state according to the checkboxes:

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)]
    });
  }
};

Finally, when you use .map on hotelRooms you can filter the list before mapping it.

{hotelRooms
  .filter((h) => filter.ratings.includes(h.hotel.starRating))
  .map((h) => (
    <div key={h.hotel.name}>
      stuff
    </div>
  ))
}

Working CodeSandbox


推荐阅读