React JS: проверьте, соответствует ли каждый элемент объекта true, а затем добавьте значки

#javascript #reactjs #react-redux

#javascript #reactjs #реагировать-redux

Вопрос:

Итак, у меня есть эти тестовые фиктивные данные здесь:

 {
    _id: "1",
    name: "Lakawon Island Resort",
    price_per_night: 2804.0,
    description:
      "On a lush 16-hectare island with white-sand beaches, this relaxed resort is 5 km from the jetty in Cadiz Viejo, a village on the mainland.",
    address: "Cadiz Viejo",
    city: "New York",
    state: "New York",
    zip_code: "6121",
    latitude: 11.045411,
    longitude: 123.201465,
    phone: "(034) 213 6354",
    email: "info@example.com",
    website: 'www.lakawonislandresort.us',
    amenities: 
      {
        tv: false,
        reservation: false,
        cabin: true,
        services: true,
    },
    image:
      "https://images.unsplash.com/photo-1512356181113-853a150f1aa7",
    rating: 4.5,
    reviews: 11,
  },
 

Обратите внимание, что у меня есть этот объект amenities , который также является объектом. В настоящее время у меня есть 4 вложенных объекта tv , reservation , cabin и services .

Что мне нужно, так это проверить каждый элемент, если они истинны, если они действительно истинны, затем верните ключ объекта и добавьте рядом с ним значок с потрясающим шрифтом. В противном случае, если значение равно false, ничего не делайте или возвращайте null.

Пока вот как я это реализовал:

{

 amenities amp;amp; Object.entries(amenities).map(
    ([key, value]) => {
        if(key === 'tv' amp;amp; key[value] === true){
            return `<p><i class="fa fa-tv"></i>  ${key}</p>`
        } else if (key === 'reservation' amp;amp; key[value] === true){
            return `<p><i class="fa fa-reservation"></i>  ${key}</p>`
        }else if (key === 'cabin' amp;amp; key[value] === true){
            return `<p><i class="fa fa-cabin"></i>  ${key}</p>`
        }else if (key === 'services' amp;amp; key[value] === true){
            return `<p><i class="fa fa-service"></i>  ${key}</p>`
        }
        
       return null
    }
)
}
 

Однако это не сработало, вместо этого оно возвращает Can't map through object ошибку.

Есть идеи, как я могу проверить каждый ключ, если они истинны, а затем вывести их соответствующий значок fontawesome рядом с ним, если значение равно true? Есть ли более эффективный способ сделать это, чем оператор if else?

Вот полный код для этого компонента:

 const Beach = ({ match }) => {
     
     const [resort, setResort] = useState({})

     useEffect(() => {
        const fetchBeach = async () => {
            const { data } = await axios.get(`/api/resorts/${match.params.id}`)
            setResort(data)
        }
 
        fetchBeach()
     }, [match])
    
    const { name, address, city, province, zip_code, image, description, amenities, website, phone, email } = resort

    return (
        <div className="row mt-5">
            <div className="col-lg-7">
            <h1>{name}</h1>
            <p><FaMapMarkerAlt /> {`${address}, ${city} ${province}, Philippines, ${zip_code}`}</p>
            <img src={image} alt={name} width="700" />
            <br/>
            <p>{description}</p>
            <br/>
            <h4>Amenities:</h4>
  <div>
  { 
  amenities amp;amp; Object.entries(amenities).map(
    ([key, value]) => {
        if(key === 'tv' amp;amp; key[value] === true){
            return `<p><i class="fa fa-tv"></i>  ${key}</p>`
        } else if (key === 'reservation' amp;amp; key[value] === true){
            return `<p><i class="fa fa-reservation"></i>  ${key}</p>`
        }else if (key === 'cabin' amp;amp; key[value] === true){
            return `<p><i class="fa fa-cabin"></i>  ${key}</p>`
        }else if (key === 'services' amp;amp; key[value] === true){
            return `<p><i class="fa fa-service"></i>  ${key}</p>`
        }
        
       return null
    }
)
}
            </div> 
        </div>



        </div>
    ) 
}

export default Beach
 

Ответ №1:

Вы можете сделать что-то более сокращенное

 {amenities amp;amp;
  Object.keys(amenities)
    .filter((key) => amenities[key])
    .map((key) => {
      if (key === "tv") {
        return (
          <p>
            <i class="fa fa-tv"></i> {key}
          </p>
        );
      } else if (key === "reservation") {
        return (
          <p>
            <i class="fa fa-reservation"></i> {key}
          </p>
        );
      } else if (key === "cabin") {
        return (
          <p>
            <i class="fa fa-cabin"></i> {key}
          </p>
        );
      } else if (key === "services") {
        return (
          <p>
            <i class="fa fa-service"></i> {key}
          </p>
        );
      }
    })}
 

Ознакомьтесь с текущим codesandbox, который я создал: https://codesandbox.io/s/optimistic-darkness-yt9sy?file=/src/Beach.js

Почему и как:

В принципе, если вам нужно только проверить, является ли ваш key === ‘something’ и проверить, является ли значение true или false, вы могли бы сделать это так:

Сначала отфильтруйте объект, чтобы он сохранял только истинные значения. Затем в вашем .map() вы узнаете, что получаете правдивые ключи, поэтому вы просто обрабатываете условный рендеринг на основе значения ключа

 .filter((key) => amenities[key]) // will filter out every values not truthy
 

myCurrentKey: » // будет отфильтрован

myCurrentKey: 1 // не будет отфильтрован

Кроме того, с моей точки зрения, когда у вас есть объект, который вы хотите отобразить, попробуйте сначала использовать Object.keys().map() , это самый простой и понятный способ сделать, если вам не нужно что-то действительно нестандартное, вы могли бы сделать с Object.entries ,или иначе.

Комментарии:

1. Ошибка типа: невозможно преобразовать undefined или null в object

2. Также в вашей песочнице кода он возвращает текст <p><i class="fa fa-cabin"></i> cabin</p><p><i class="fa fa-service"></i> services</p>; } вместо форматированного HTML

3. Что касается первого комментария, то, поскольку вы не можете отобразить что-то нулевое, вам нужно вернуть пустую строку. Во-вторых, это потому, что в вашем первом коде вы вернули строку шаблона, когда вам просто нужно вернуть html напрямую без строки. Вот и все

Ответ №2:

Это можно сделать и таким образом:

 const { amenities = {} } = resort;

return (
    <div>
        {Object.keys(amenities).map(item => {
            return amenities[item] ? <p><i class={`fa fa-${item}`}></i>{item}</p> : null;
        })}
    </div>
)
 

Но я думаю, что отображение здесь на самом деле не нужно, и вы можете просто упростить его:

 const { amenities = {} } = resort;

return (
    <div>
        {amenities.tv amp;amp; <p><i class="fa fa-tv"></i>tv</p>}
        {amenities.reservation amp;amp; <p><i class="fa fa-reservation"></i>reservation</p>}
        {amenities.cabin amp;amp; <p><i class="fa fa-cabin"></i>cabin</p>}
        {amenities.services amp;amp; <p><i class="fa fa-service"></i>services</p>}
    </div>
)
 

Ответ №3:

Попробуйте это:

 amenities amp;amp; Object.entries(amenities).filter(([key,value]) =>  value === true).map(
    ([key]) => {
        switch(key){
            case 'tv':
                return <p><i class="fa fa-tv"></i> {key}</p>;
            case 'reservation':
                return <p><i class="fa fa-reservation"></i> {key}</p>;
            case 'cabin':
                return <p><i class="fa fa-cabin"></i> {key}</p>;
            case 'services':
                return <p><i class="fa fa-services"></i> {key}</p>;
            default:
                return null;
        }
    })
 

Я думаю, ваша проблема в том, что вы используете key[value] when key — строка и value является логическим значением

Комментарии:

1. Он возвращает текст, а не тег абзаца. Вот что его возвращает <p> tv</p><p>reservation</p> Это должен быть абзац а не написанный html текст

2. Вы правы, я этого не заметил. попробуйте обновленный код прямо сейчас