Home > Back-end >  How can I make this map filter shorter & better
How can I make this map filter shorter & better

Time:04-13

I think this is not an ideal way of doing filters. I have to type more if else's and it doesn't look good.

I found a package called "useFilter". but can I just make it without using any packages? like with hooks or something.

 
import { AddPosition } from "./../../data/careers/AddPosition";

const Positions = () => {
  const [positions] = useState(AddPosition);
  const [searchTerm, setSearchTerm] = useState("");

   <input
                type="search"
                placeholder="Search"
                onChange={(e) => setSearchTerm(e.target.value)}
              />
             
                   {positions
            .filter((position) => {
              if (searchTerm === "") {
                return position;
              } else if (
                position.category
                  .toLowerCase()
                  .includes(searchTerm.toLowerCase())
              ) {
                return position;
              } else if (
                position.type.toLowerCase().includes(searchTerm.toLowerCase())
              ) {
                return position;
              } else if (
                position.location
                  .toLowerCase()
                  .includes(searchTerm.toLowerCase())
              ) {
                return position;
              } else if (
                position.position
                  .toLowerCase()
                  .includes(searchTerm.toLowerCase())
              ) {
                return position;
              }
            })
            .map((position) => (
              <>
                <SinglePosition
                  id={position.id}
                  category={position.category}
                  type={position.type}
                  position={position.position}
                />
              </>
            ))}
        </div>
      </div>
    </div>

CodePudding user response:

You can simplify this by using Array.prototype.some and you can also use useMemo to make sure that the filtering happens only when positions/searchTerm changes.

const filteredPositions = useMemo(() => {
      if(!searchTerm) return positions;
      const lowerCasedSearchTerm = searchTerm.toLowerCase();
      return positions.filter(({id, ...other}) => {
          // assuming you want to check every value in position
          return Object.values(other).map(v => v.toLowerCase()).some(v => v.includes(lowerCasedSearchTerm))
      })
  }, [positions, searchTerm])

Now you can map filteredPositions in the JSX.

CodePudding user response:

You're logic is repeated for each property of position. Combine them to a single array, and iterate it with Array.some() if any of the includes the term, it would return true:

{positions
  .filter(({ id, ...rest }) => {
    const term = searchTerm.toLowerCase();

    return !term || Object.values(rest).some(str =>
      str.toLowerCase().includes(term)
    );
  })
  .map(position => (
    <SinglePosition key={position.id} {...position} />
  ))
}

Note: when rendering a list of items don't forget to include a key property. In addition, you don't need to wrap a single element in a fragment. You need a fragment only if you render multiple elements without a single parent.

  • Related