【问题标题】:how to map array of images into two images per list item React JS如何将图像数组映射为每个列表项 React JS 的两个图像
【发布时间】:2023-03-12 15:27:01
【问题描述】:

我想为每个列表项映射两个图像。

我有一个滑块,每个视图会显示两张幻灯片,所以我希望它每次视图显示 4 张图片。

目前,它只是显示相同的图像,这是我期望它做的,我只是不知道如何为每个列表项映射两个不同的图像。

我将如何映射此数组以使每个列表项都有两个不同的图像?

SliderComponent.js

import React, { useState, useEffect, useRef } from "react";
import { IonGrid, IonRow, IonCol } from '@ionic/react';
import { Storage } from "aws-amplify";
import Slider from "react-slick";
import "slick-carousel/slick/slick.css";


const SliderComponent = (props) => {

    const { job } = props;
    const [images, setImages] = useState([]);


    const settings = {
        infinite: false,
        slidesToShow: 2,
        slidesToScroll: 2,
        speed: 500,
        rows: 1,
        initialSlide: 0,
        autoHeight: false,
        focusOnSelect: true,
        arrows: false,
    };


    useEffect(() => {
        async function onLoad() {

            try {
                const downloadedImage = await getImage(job);
                setImages(downloadedImage);
            } catch (e) {
                alert(e);
            }
        }

        onLoad();
    }, []);


    async function getImage(jobID) {
        const imageURL = await Storage.list(`${jobID}/completed/`);
        let imagesToDownload = imageURL
        let imagesAsArray = [];
        for (let i = 0; i < imagesToDownload.length; i++) {
            const imagesDownloaded = await getURLFromS3(imagesToDownload[i]);
            imagesAsArray.push(imagesDownloaded)
        }
        return imagesAsArray
    }

    async function getURLFromS3(fileToDownload) {
        const result = await Storage.get(fileToDownload.key)
        return result;
    }

   return (

        <div>
            <IonGrid>
                <IonRow style={{ justifyContent: 'center' }}>
                    <IonCol sizeXs="12" sizeSm="12" sizeMd="10" sizeLg="6" sizeXl="4" >
                        <Slider asNavFor={nav1} ref={slider => (slider2.current = slider)} {...viewSettings}>
                            {images.map((image, i) =>
                                <ul>
                                    <li><img key={i} src={image} /></li> /// First image
                                    <li><img key={i} src={image} /></li> /// Second image
                                </ul>
                            )}
                        </Slider>
                    </IonCol>
                </IonRow>
            </IonGrid>
        </div>
    )
}
export default SliderComponent;

props.job 页面

import React, { useState, useEffect } from "react";
import { withRouter } from 'react-router-dom';
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar, IonGrid, IonCol, IonRow, } from '@ionic/react';
import { API, Auth } from "aws-amplify";
import SliderComponent from '../components/sliderComponent.js'


function propertyInfo(props) {


    return (
        <IonPage>
            <IonHeader>
                <IonToolbar>
                    <IonTitle>prop address</IonTitle>
                </IonToolbar>
            </IonHeader>
            <IonContent>

            <SliderComponent job={props.match.params.id} />

            </IonContent>
        </IonPage>
    );
}
export default withRouter(propertyInfo);

【问题讨论】:

  • 你能把props.job代码包括进来吗?
  • @Skoltz 已编辑!

标签: arrays reactjs mapping


【解决方案1】:

您可以在映射之前对图像数组进行分块。如果你的应用有lodash,你可以使用_.chunk函数:

lodash _.chunk(array, [size=1])

创建一个元素数组,按照大小的长度分成组。如果数组不能被平均分割,最后的块将是剩余的元素。

你也可以用几行代码编写自己的块函数:

function chunk(array, size) {
  const chunked_arr = [];
  let index = 0;
  while (index < array.length) {
    chunked_arr.push(array.slice(index, size + index));
    index += size;
  }
  return chunked_arr;
}

结果(注意:正如@HMR 指出的那样,image2 是有条件地呈现的,因为如果您的图像数组是奇数,那么您的最后一个块将只有一个元素并且会呈现损坏的图像标签):

{chunk(images, 2).map(([image1, image2], i) =>
  <ul key={i}>
    <li><img src={image1} /></li>
    {image2 && <li><img src={image2} /></li>}
  </ul>
)}

【讨论】:

  • 图片为奇数时会报错。为你可以用 12 行代码编写的东西添加 lodash 可能不是最好的主意
  • @HMR - 你是对的,如果最后一个块只包含 1 个元素,就会有一个损坏的图像标签。我修改了示例来处理这种情况。如果 lodash 不是一个选项,我还添加了一个自定义块函数。
【解决方案2】:

您可以使用 zip,它需要 x 个数组并返回一个数组,其中每个元素都是传递的数组的一个元素。所以对于[1,2] 和[3,4],它将返回[[1,3],[2,4]]。

当您传递相同的数组但第二个数组是 slice(1)(没有第一个元素)时,您将传递 [1,2] 和 [2] 导致 [[1,2],[2,undefined]],然后过滤掉所有在奇数索引中的元素你会得到[[1,2]]。这是一个例子:

const zip = (...arrays) =>
  [
    ...new Array(
      Math.max(...arrays.map((array) => array.length))
    ),
  ].map((_, index) => arrays.map((array) => array[index]));
const array = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
console.log(
  '2 imamages',
  zip(array, array.slice(1)).filter(
    (_, index) => index % 2 === 0
  )
);
console.log(
  '3 imamages',
  zip(array, array.slice(1), array.slice(2)).filter(
    (_, index) => index % 3 === 0
  )
);

所以现在你可以这样做了:

{zip(images, images.slice(1))
  .filter((_, index) => index % 2 === 0)
  .map(([image1,image2], i) =>
  <ul key={i}>
      <li><img src={image1} /></li> /// First image
      <li>{image2 && <img src={image2} />}</li> /// Second image
  </ul>
)}

请注意,如果您有奇数个图像,那么在某些时候image2 是未定义的,这就是为什么如果有图像,则有条件地渲染第二个图像。我还更正了 key prop,你需要在根元素上设置它。

如果你更喜欢块,那么一旦你有 zip 块就是小菜一碟:

const zip = (...arrays) =>
  [
    ...new Array(
      Math.max(...arrays.map((array) => array.length))
    ),
  ].map((_, index) => arrays.map((array) => array[index]));
const chunk = (array, items) =>
  zip(
    ...[...new Array(items)].map((_, index) =>
      array.slice(index)
    )
  ).filter((_, index) => index % items === 0);
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9];

console.log('2 imamages', chunk(array, 2));
console.log('3 imamages', chunk(array, 3));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-13
    相关资源
    最近更新 更多