'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 enter image description here

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