0

I have an array of images and I wanted to them to be in ascending order. My problem is I want the first image to be on the <CardMedia/> while the other remaining images to be put on <img>. What will be the most ideal way to do this using the latest version of JS?

Codesandbox -> CLICK HERE

Code

    export default function BasicCard() {
      const orderImages = images.sort(function (a, b) {
    return a.order - b.order;
  });
    
      return (
        <Card>
          <Stack spacing={1}>
            <CardMedia
              component="img"
              image={orderImages?.[0]?.url}
              sx={{
                maxHeight: { xs: 100, sm: 100 },
                objectFit: "cover"
              }}
            />
            <Grid container spacing={0.5}>
              {orderImages?.map((image) => (
                <Grid key={image.order} item xs={4}>
                  <img src={image.url} width="100%" />
                </Grid>
              ))}
            </Grid>
          </Stack>
        </Card>
      );
    }

Expected Output below

Card Media

  {
    order: 0,
    url: "https://source.unsplash.com/user/c_v_r/1900x800"
  },

Img src

    {
        order: 1,
        url: "https://html.com/wp-content/uploads/flamingo.jpg"
      },
       {
    order: 5,
    url:
      "https://res.cloudinary.com/demo/image/upload/if_ar_gt_3:4_and_w_gt_300_and_h_gt_200,c_crop,w_300,h_200/sample.jpg"
  }
Joseph
  • 7,042
  • 23
  • 83
  • 181
  • after the `const orderImages` you could try `const heroImage = orderImages.shift()` and use heroImage in the CardMedia – Emile Oct 07 '22 at 09:39
  • @Emile. Not sure what you mean? – Joseph Oct 07 '22 at 09:43
  • Inside map() as the second parameter of the callback function, we get the index. Now you will use conditional rendering like if the index is equal to zero then render CardMedia else img – Arifur Rahaman Oct 07 '22 at 10:02

2 Answers2

3

It's a good idea to maintain immutability because it makes it easier to reason about your code:

const orderImages = images.sort(function (a, b) {
    return a.order - b.order;
});

This function is actually changing the images array. which is quite bad because it creates hard to find bugs. What's happening here is:

  • images.sort changes the images array and passes the reference (check this thread for a good explanation on how JS treats Arrays) to your orderImages variable
  • const heroImage = orderImages.shift(); (in your CodeSandbox) is removing the first element from the array (which, remember, is the images array)

So once you get to render it it's already a mess. Plus, I'm not sure how CodeSandbox works but I think the application re-renders without reloading the images array, so you'll be using the modified version in memory every time you save the file (without a full reload), which means the array will have 1 less element for every time orderImages.shift() runs.

The way I'd do this safely would be something like this:

export default function BasicCard() {
  // using the spread operator copies the array
  // so you're not modifying the original array
  const orderImages = [...images].sort(function (a, b) {
    return a.order - b.order;
  });

  // This syntax extracts the 1st element of the array
  // as well as the "rest" of it (with the 1st element removed)
  // but if you check orderImages, it's still intact
  const [first, ...rest] = orderImages;

  return (
    <Card>
      <Stack spacing={1}>
        <CardMedia
          component="img"
          image={first.url}
          sx={{
            maxHeight: { xs: 100, sm: 100 },
            objectFit: "cover"
          }}
        />
        <Grid container spacing={0.5}>
          {rest.map((image) => (
            <Grid key={image.order} item xs={4}>
              <img src={image.url} width="100%" />
            </Grid>
          ))}
        </Grid>
      </Stack>
    </Card>
  );
}
Pedro Filipe
  • 995
  • 1
  • 8
  • 17
0

You can use Array destructuring to achieve that:

const [firstImage, ...otherImages] = orderImages;
  • firstImage contains the first image --> Card Media
  • otherImages contains an array of all the other images --> Image src
David
  • 743
  • 4
  • 7