Home > Back-end >  How to output the values of an object in an array if one of the object's values matches a value
How to output the values of an object in an array if one of the object's values matches a value

Time:10-05

If I have this array:

const data = [
    {
      id: 1,
      category: "ladders",
      name: "N/A",
      price: 0,
    },
    {
      id: 2,
      category: "ladders",
      name: "Ladder 1",
      price: 220,
    },
    {
      id: 3,
      category: "ladders",
      name: "Ladder 2",
      price: 420,
    },
    {
      id: 4,
      category: "ladders",
      name: "Ladder 3",
      price: 515,
    },
]

And I have this in my useState hook:

  const [selections, setSelections] = useState({
    ladders: [2, 4]
  });

I'm trying to output in my JSX the values of the objects in data that have a matching 'id' to the values in my 'ladders' property in my useState hook (i.e. 2 and 4). I can do it by manually specifying the array indexes, like so:

{data
  .filter((item) => item.id === selections.ladders[0])
  .map((item) => {
    return (
      <li className="item" key={item.id}>
        <div className="item__body">
          <h3 className="item__name">{item.name}</h3>
        </div>
        <span className="item__price">£{item.price}</span>
      </li>
    );
  })}

{data
  .filter((item) => item.id === selections.ladders[1])
  .map((item) => {
    return (
      <li className="item" key={item.id}>
        <div className="item__body">
          <h3 className="item__name">{item.name}</h3>
        </div>
        <span className="item__price">£{item.price}</span>
      </li>
    );
  })}

But how I can refactor this so I don't have to manually specify the 'ladders' array indexes? Any help appreciated.

CodePudding user response:

Just check whether ladders includes the ID:

.filter((item) => selections.ladders.includes(item.id))

CodePudding user response:

You can use Array.prototype.includes.

{data
  .filter((item) => selections.ladders.includes(item.id))
  .map((item) => {
    return (
      <li className="item" key={item.id}>
        <div className="item__body">
          <h3 className="item__name">{item.name}</h3>
        </div>
        <span className="item__price">£{item.price}</span>
      </li>
    );
  })}

If you can change the structure of data, you can actually change it to an object for a bit more performance.

{
    "1": {
        "id": 1,
        "category": "ladders",
        "name": "N/A",
        "price": 0
    },
    "2": {
        "id": 2,
        "category": "ladders",
        "name": "Ladder 1",
        "price": 220
    },
    "3": {
        "id": 3,
        "category": "ladders",
        "name": "Ladder 2",
        "price": 420
    },
    "4": {
        "id": 4,
        "category": "ladders",
        "name": "Ladder 3",
        "price": 515
    }
}

Then you can do setSelected(prev=>[...prev, item.id]). And for rendering:

{selected
  .map((id) => {
    return (
      <li className="item" key={id}>
        <div className="item__body">
          <h3 className="item__name">{data[id].name}</h3>
        </div>
        <span className="item__price">£{data[id].price}</span>
      </li>
    );
  })}

If you don't have access to data, you can use a Set. Checking if an element is in a set is O(1) as compared to O(n) for Array.includes.

  • Related