I have this program that should show all of my images and when I click a check box, filter them down to the specified attribute. However, it only seems to work once when I reload the page and then any time I click a checkbox the filter doesn’t update. I am new to react, am i using setState or handleChange wrong?
import React, { useState } from 'react';
import FilterBar from './FilterBar';
const images = [
{ id: 1, colour: 'colour', location: 'Rocky Mountains', theme: 'landscape', url: "images/websiteimage1.jpg" },
{ id: 2, colour: 'colour', location: 'Rocky Mountains', theme: 'landscape', url: "images/websiteimage2.jpg" },
{ id: 3, colour: 'colour', location: 'Rocky Mountains', theme: 'animals', url: "images/websiteimage15.jpg" },
{ id: 4, colour: 'colour', location: 'Rocky Mountains', theme: 'animals', url: "images/websiteimage18.jpg" },
{ id: 5, colour: 'colour', location: 'Johnstown', theme: 'architecture', url: "images/websiteimage55.jpg" },
{ id: 6, colour: 'colour', location: 'Drumheller', theme: 'architecture', url: "images/websiteimage51.jpg" },
];
const Gallery = () => {
const [filters, setFilters] = useState({
colour: [],
location: [],
theme: []
});
const handleChange = (category, value) => {
setFilters((filters) => {
const newFilters = { ...filters };
if (newFilters[category].includes(value)) {
newFilters[category] = newFilters[category].filter(item => item !== value);
} else {
newFilters[category].push(value);
}
return newFilters;
});
};
const filteredImages = images.filter(image => {
return (
(filters.colour.length === 0 || filters.colour.includes(image.colour)) &&
(filters.location.length === 0 || filters.location.includes(image.location)) &&
(filters.theme.length === 0 || filters.theme.includes(image.theme))
);
});
return (
<div>
<div className="filter-bar">
<div className="filter-category">
<h3>Colour</h3>
<label>
<input
type="checkbox"
checked={filters.colour.includes('b/w')}
onChange={() => handleChange('colour', 'b/w')}
/>
B/W
</label>
<label>
<input
type="checkbox"
checked={filters.colour.includes('colour')}
onChange={() => handleChange('colour', 'colour')}
/>
Colour
</label>
</div>
<div className="filter-category">
<h3>Location</h3>
<label>
<input
type="checkbox"
checked={filters.location.includes('Johnstown')}
onChange={() => handleChange('location', 'Johnstown')}
/>
Johnstown
</label>
<label>
<input
type="checkbox"
checked={filters.location.includes('St Lawrence River')}
onChange={() => handleChange('location', 'St Lawrence River')}
/>
St Lawrence River
</label>
<label>
<input
type="checkbox"
checked={filters.location.includes('Rocky Mountains')}
onChange={() => handleChange('location', 'Rocky Mountains')}
/>
Rocky Mountains
</label>
<label>
<input
type="checkbox"
checked={filters.location.includes('Drumheller')}
onChange={() => handleChange('location', 'Drumheller')}
/>
Drumheller
</label>
<label>
<input
type="checkbox"
checked={filters.location.includes('Charleston Lake')}
onChange={() => handleChange('location', 'Charleston Lake')}
/>
Charleston Lake
</label>
</div>
<div className="filter-category">
<h3>Theme</h3>
<label>
<input
type="checkbox"
checked={filters.theme.includes('landscape')}
onChange={() => handleChange('theme', 'landscape')}
/>
Landscape
</label>
<label>
<input
type="checkbox"
checked={filters.theme.includes('animals')}
onChange={() => handleChange('theme', 'animals')}
/>
Animals
</label>
<label>
<input
type="checkbox"
checked={filters.theme.includes('people')}
onChange={() => handleChange('theme', 'people')}
/>
People
</label>
<label>
<input
type="checkbox"
checked={filters.theme.includes('architecture')}
onChange={() => handleChange('theme', 'architecture')}
/>
Architecture
</label>
</div>
</div>
<div className="image-gallery">
{filteredImages.map(image => (
<img key={image.id} src={process.env.PUBLIC_URL + image.url} alt={image.category} />
))}
</div>
</div>
);
};
export default Gallery;
I had originally put filter Bar in its own component and moved it directly into gallery because I wasn’t sure that you could change props inside the child element. I am not sure what to try, reading line by line it seems to at least make sense to me, but I am not sure