Home > OS >  How can I show certain elements from an array based on a React State?
How can I show certain elements from an array based on a React State?

Time:05-01

I am a relatively new React developer, and I am attempting to show only certain services that have a serviceType of either exterior, interior, combo, or add on. As of now, I have mapped these services into a react component and I am able to display every service that I pull from my database. However, I would like to only display "exterior" services or "interior" services based on the user's selection.

My current code is as follows:

import React, { useEffect, useState } from 'react';
import Service from './Service';
import OffersService from '../../../services/OffersService';
import Button from '../../UI/Button';

const ServiceList = props => {
    const [offers, setOffers] = useState([]);
    const [service, setService] = useState('Exterior');

    const exteriorTypeHandler = () => {
        setService('Exterior');
    };

    const interiorTypeHandler = () => {
        setService('Interior');
    };

    const comboTypeHandler = () => {
        setService('Combo');
    };

    const addonsTypeHandler = () => {
        setService('Add Ons');
    };

    const offersList = offers.map(offer => (
        <Service
            key={offer.id}
            code={offer.serviceCode}
            name={offer.serviceName}
            description={offer.description}
            type={offer.serviceType}
            price={offer.salePrice}
        />
    ));

    useEffect(() => {
        getAllOffers();
    }, []);

    const getAllOffers = () => {
        OffersService.getAllServices()
            .then(response => {
                setOffers(response.data);
            })
            .catch(err => {
                console.log(err);
            });
    };

    return (
        <div>
            <div className='flex justify-center space-x-4'>
                <Button name='Exterior' onClick={exteriorTypeHandler} />
                <Button name='Interior' onClick={interiorTypeHandler} />
                <Button name='Combos' onClick={comboTypeHandler} />
                <Button name='Add Ons' onClick={addonsTypeHandler} />
            </div>

            <ul>{offersList}</ul>
        </div>
    );
};

export default ServiceList;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

In an attempt to get the results I'd like to see, I've tried the following code for my :

<ul>
  {offersList.forEach(offer => {
        if (offer.serviceType === service) {
        return offer;
        }
  })}
</ul>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

I have also tried: {offersList.serviceType === service && <ul>{offersList}</ul>}

I haven't been able to find anything to help in my Udemy lectures, YouTube, or other Stack Overflow posts, so I appreciate any help that can be given!

CodePudding user response:

First off, I am assuming the response.data is being fetched successfully. I like the approach but a little refactoring can be done. First off, if all the button names are actual serviceTypes from the fetched data, then my solution should work. Ideally, you want to use one onClick function for each button element. In this case, we have something that can delineate from the other Buttons and that is their name.

So all we need to do is grab that name using event from the onClick handler (it looks like this in the code: e.target.name), save the name in our state for asynchronous filtering, and compare offer.serviceType to our currentService while looping through. We use map instead of forEach because we need to actually allocate memory and display them in the DOM.

EDIT: Also, notice how I rendered the fetched data in return. I used a ternary operator to make sure that the request was completed and the data stored in memory before we attempt to access it using map. I forgot to the mention this too - if the serviceTypes from the database are not the matching the names on the Buttons, make sure to fix that for this to work.

import React, { useEffect, useState } from 'react';
import Service from './Service';
import OffersService from '../../../services/OffersService';
import Button from '../../UI/Button';

const ServiceList = props => {
    const [offers, setOffers] = useState([]);
    const [currentService, setCurrentService]

    const onClickTypeHandler = (e) =>{
        console(e.target.name)
        setCurrentService(e.target.name)
    }

    const offersList = offers.map(offer => (
        <Service
            key={offer.id}
            code={offer.serviceCode}
            name={offer.serviceName}
            description={offer.description}
            type={offer.serviceType}
            price={offer.salePrice}
        />
    ));

    useEffect(() => {
        getAllOffers();
    }, []);

    const getAllOffers = () => {
        OffersService.getAllServices()
            .then(response => {
                setOffers(response.data);
            })
            .catch(err => {
                console.log(err);
            });
    };

    return (
        <div>
            <div className='flex justify-center space-x-4'>
                <Button name='Exterior' onClick={onClickTypeHandler} />
                <Button name='Interior' onClick={onClickTypeHandler} />
                <Button name='Combos' onClick={onClickTypeHandler} />
                <Button name='Add Ons' onClick={onClickTypeHandler} />
            </div>

            <ul>{offersList ? offersList.map(offer => {
                if (offer.serviceType === currentService){
                    return <p>{offer}</p>
                }
            }) : ''}</ul>
        </div>
    );
};

export default ServiceList;

CodePudding user response:

<ul>
  {offersList.map(offer => {
        if (offer.serviceType === service) {
        return <li> offer </li>;
        }
  })}
</ul>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

You need to use map instead of forEach and return offer wrapped in <li></li> tag.

  • Related