'How to use React to create a checkboxes filter function?
I want to create a filter function in my collection page, when checking one checkbox, and that type of resorts will be rendered.
So in my CollectionPage.js, after fetching all resorts and setting the Resorts state, according to the type param in the url
const { type } = useParams();
I prepared the array of type objects for the FilterBox.js to use. And the type that match the url param will be Selected: true
const [resorts, setResorts] = useState([]);
const { type } = useParams();
useEffect(() => {
fetch("https://......")
.then(response => response.json())
.then(json => {
setResorts(json);
}).catch(err => {
console.log(`Error ${err}`)
})
}, [])
/* get all types array */
const allType = ["All"];
resorts.map(item => (allType.push(item.Type)));
/* get no-repeat types array */
const collection = allType.filter(
(ele, pos) => {
return allType.indexOf(ele) === pos;
}
)
/* set types array for filterBox to use */
const typeObjs = [];
collection.map(item => (
item === type ? (
typeObjs.push({ Type: item, Selected: true })
) : (
typeObjs.push({ Type: item, Selected: false })
)
));
Then, in the child component - FilterBox.js, it receive the typeObjs array as type, to render checkboxes
const FilterBox = ({ type }) => {
return (
<div className='filter-box'>
<div className='filter-card'>
<h3>Select Resorts Type</h3>
<div className='filter-selection'>
{
type.map(item => (
item.Selected === false ? (
<div>
<Link to = {`/resorts/type/${item.Type}`}>
<input type="checkbox" id={item.Type} name="type" value={item.Type} />
<label htmlFor={item.Type}> {item.Type}</label>
</Link>
</div>
) : (
<div>
<Link to = {`/resorts/type/${item.Type}`}>
<input type="checkbox" id={item.Type} name="type" value={item.Type} defaultChecked />
<label htmlFor={item.Type}> {item.Type}</label>
</Link>
</div>
)
))
}
</div>
</div>
</div>
)
}
As you can see, checkbox will be checked if it match the current page url param

And I have wrapped each checkbox within a tag which will link to the relative type url
<div>
<Link to = {`/resorts/type/${item.Type}`}>
<input type="checkbox" id={item.Type} name="type" value={item.Type} />
<label htmlFor={item.Type}> {item.Type}</label>
</Link>
</div>
The issue is, when I click other type, the defaultChecked "All" type wil still be checked, and what I click will not be checked but, the relative resorts will be rendered successfully. Have no idea how to solve this.
Thank you for your time of checking my issue and I appreciate for your help!
Solution 1:[1]
Take a look at Sandbox. it creates a custom hook, useSingleSelect. It handles an array state whose length is 0 or 1.
useSingleSelect.ts
import React, { useState } from "react";
export const useSingleSelect = (initialValue: string[]) => {
const [selected, setSelected] = useState<string[]>(initialValue);
const onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const value = event.target.value;
if (selected.includes(value)) {
setSelected([]);
} else {
setSelected([value]);
}
};
const isSelected = (value: string) => {
return selected.includes(value);
};
return { selected, isSelected, onChange };
};
App.tsx
import { useSingleSelect } from "./hooks";
const data = ["All", "Resort", "Apartment", "Villa", "Hostel", "Cottage"];
export default function App() {
const { selected, isSelected, onChange } = useSingleSelect(['All']);
return (
<div>
<div>Selected: {selected.join()}</div>
<ul style={{ listStyleType: "none" }}>
{data.map((value) => (
<li key={value}>
<input
id={value}
type="checkbox"
value={value}
checked={isSelected(value)}
onChange={onChange}
/>
<label htmlFor={value}>{value}</label>
</li>
))}
</ul>
</div>
);
}
https://codesandbox.io/s/usesingleselect-llor3k?file=/src/App.tsx
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
