David
David

Reputation: 67

Data in array items not being displayed on the screen in React

I'm making a simple React app where I am getting a list of cars through useEffect hook and then mapping through each one to display them on the screen. Then, I have one button whose purpose would be to sort the cars based on their horsepower. So, when clicking on that button the user would see only the cars whose horsepower is greater than for example 700.


import React, { useState, useEffect } from "react";
import "./style.css";

export default function App() {

  const [items, setItems] = useState([])
  const [yo, setYo] = useState(false)
  
useEffect(() => {
    fetch("https://private-anon-af560a53c6-carsapi1.apiary-mock.com/cars")
      .then(res => res.json())
      .then(data => {
        setItems(data)
      })
  }, [])


  function reverse(){
    items.reverse();
    setItems([...items])
  }

  function sortHigherHP(){
    let cars = items.filter(item => {
      return item.horsepower >= 700;
    }).map(i => {
      return(
        <div key={Math.floor(Math.random()*10000)} style={{border: "1px solid black", margin: "10px", padding: "5px"}}>
            <p>Make: {i.make}</p>
            <p>Horsepower: {i.horsepower} HS</p>
          </div>
      )
    });
    setItems(cars)
  }

  function hey(){
    setYo(!yo)
  }  

  return (
    <div>
      <h1>React Search &amp; Filter</h1>
      <div>
        <h3 onClick={hey}>Sort</h3>
        <div className={yo ? "show" : "hide"}>Sorting options
          <button onClick={reverse}>Reverse Order</button>
          <button onClick={sortHigherHP}>Higher Horsepower</button>
        </div>
      </div>
      {items.slice(0, 50).map(a => {
        return (
          <div key={Math.floor(Math.random()*10000)} style={{border: "1px solid black", margin: "10px", padding: "5px"}}>
            <p>Make: {a.make}</p>
            <p>Horsepower: {a.horsepower} HS</p>
          </div>
        )
      })}
    </div>
  );
}

The reverse event handler is obviously working since the reverse method just reverses the array, without changing the original array. But this filter method returns a new array and I have problems here on how to actually display data on the screen. Could the problem be in the .map method that comes right after .filter()?

Upvotes: 1

Views: 184

Answers (1)

bas
bas

Reputation: 15462

Could the problem be in the .map method that comes right after .filter()?

Yes this is indeed the problem:

function sortHigherHP() {
  let cars = items
    .filter((item) => {
      return item.horsepower >= 700;
    })
    .map((i) => {
      return (
        <div
          key={Math.floor(Math.random() * 10000)}
          style={{
            border: "1px solid black",
            margin: "10px",
            padding: "5px",
          }}
        >
          <p>Make: {i.make}</p>
          <p>Horsepower: {i.horsepower} HS</p>
        </div>
      );
    });
  setItems(cars);
}

You should remove the map in its entirety here:

function sortHigherHP() {
  let cars = items.filter((item) => {
    return item.horsepower >= 700;
  });

  setItems(cars);
}

You already have a map call that handles displaying your items:

{
  items.slice(0, 50).map((a) => {
    return (
      <div
        key={Math.floor(Math.random() * 10000)}
        style={{
          border: "1px solid black",
          margin: "10px",
          padding: "5px",
        }}
      >
        <p>Make: {a.make}</p>
        <p>Horsepower: {a.horsepower} HS</p>
      </div>
    );
  });
}

Because of the extra map call you're actually setting the items state to jsx instead of an array of objects, which makes the code above not work.

Codesandbox example

Upvotes: 1

Related Questions