Home > database >  Put Images in Order in React/ES6
Put Images in Order in React/ES6

Time:10-07

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"
  }

CodePudding user response:

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>
  );
}

CodePudding user response:

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
  • Related