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.