1

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.

2 Answers 2

3

Just check whether ladders includes the ID:

.filter((item) => selections.ladders.includes(item.id))
Sign up to request clarification or add additional context in comments.

Comments

1

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.

1 Comment

@peardrops added some extra info if you're looking to optimize your code

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.