Удалить значение из массива при нажатии React. js - PullRequest
2 голосов
/ 27 мая 2020

Я создаю слайдер изображений, который отображает и перечисляет массив URL-адресов изображений.

Я пытаюсь сохранить массив URL-адресов изображений, которые пользователь хочет скрыть от просмотра.

Мой план - сохранить значение массива в таблице DynamoDB , затем извлеките массив URL-адресов, которые не должны отображаться, а затем отфильтруйте их из сопоставленных изображений в ползунке.

У меня есть значок EyeOFF, показанный над изображением, которое они щелкают, и который переключает icon скрыть true и false с помощью свойства onClick изображения и значка. --- см. const handleBottomImageClick().

Моя проблема в том, что я не могу удалить значение изображения (img url) из массива, сохраненного в переменной состояния selectedImage. --- см. const handleTopImageClick().

Я пробовал array.pop() и array.splice(), но я не знаю, будут ли эти методы работать эффективно для того, что я пытаюсь сделать.

Ползунок

import React, { useState, useEffect, useRef } from "react";
import { IonModal, IonContent, IonButton, IonIcon, IonGrid, IonRow, IonCol, IonItem, IonLabel } from '@ionic/react';
import { chevronBackOutline, chevronForwardOutline } from 'ionicons/icons';
import { Storage } from "aws-amplify";
import Image from '../components/SliderImages.js';
import FullImage from '../components/LargeSliderImage.js';
import Slider from "react-slick";
import "slick-carousel/slick/slick.scss";
import { chunk } from 'lodash';
import Modal from 'react-modal';
import { eyeOffOutline, createSharp, shareSharp } from 'ionicons/icons';




const SliderComponent = (props) => {

    const { job, hideImages } = props;
    const [selectedImage, setSlectedImage] = useState([]);
    const [images, setImages] = useState([]);
    const [showModal, setShowModal] = useState(false);
    const [activeSlide, setActiveSlide] = useState(false);
    const [initialSlide, setInitialSlide] = useState(0)
    const [state, setState] = useState({
        nav1: null,
        nav2: null
    });
    const slider1 = useRef();
    const slider2 = useRef();

       let imagesToHide = [];

    const SlickArrowLeft = ({ ...props }) => (

        <IonIcon  {...props} type="button" size="large" icon={chevronBackOutline} />

    );

    const SlickArrowRight = ({ ...props }) => (
        <IonIcon {...props} type="button" size="large" icon={chevronForwardOutline} />
    );


    const customStyles = {
        content: {
            top: '50%',
            left: '50%',
            right: 'auto',
            bottom: 'auto',
            marginRight: '-50%',
            transform: 'translate(-50%, -50%)'
        }
    };

    useEffect(() => {
        setState({
            nav1: slider1.current,
            nav2: slider2.current
        });
    }, []);

    const {
        nav1,
        nav2
    } = state;

    const settings = {
        infinite: false,
        lazyLoad: "ondemand",
        useCSS: true,
        useTransform: true,
        slidesToShow: 5,
        slidesToScroll: 5,
        speed: 500,
        initialSlide: 0,
        autoHeight: false,
        draggable: true,
        arrows: true,
        prevArrow: <SlickArrowLeft class="prevArrowButton" />,
        nextArrow: <SlickArrowRight class="nextArrowButton" />,

        responsive: [
            {
                breakpoint: 1024,
                settings: {
                    lazyLoad: "ondemand",
                    slidesToShow: 4,
                    slidesToScroll: 4,
                    speed: 500,
                    initialSlide: 0,
                    autoHeight: false,

                    arrows: false,
                }
            },
            {
                breakpoint: 600,
                settings: {
                    lazyLoad: "ondemand",
                    slidesToShow: 3,
                    slidesToScroll: 3,
                    speed: 500,
                    initialSlide: 0,
                    autoHeight: false,

                    arrows: false,

                }
            },
            {
                breakpoint: 480,
                settings: {
                    lazyLoad: "ondemand",
                    slidesToShow: 2,
                    slidesToScroll: 2,
                    speed: 500,
                    initialSlide: 0,
                    autoHeight: false,

                    arrows: true,
                    prevArrow: <SlickArrowLeft class="prevArrowButton" />,
                    nextArrow: <SlickArrowRight class="nextArrowButton" />,
                }
            }
        ]
    };

    const viewSettings = {
        infinite: true,
        lazyLoad: "ondemand",
        slidesToShow: 1,
        slidesToScroll: 1,
        speed: 500,
        autoHeight: false,
        focusOnSelect: false,
        initialSlide: initialSlide,
        arrows: true,
        prevArrow: <SlickArrowLeft class="prevArrowButton" />,
        nextArrow: <SlickArrowRight class="nextArrowButton" />,

    }


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

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

        onLoad();
    }, [job]);


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


    const handleBottomImageClick = function (index, image2) {
        if (hideImages) {
            if (selectedImage[image2]) {
                setSlectedImage({ ...selectedImage, [image2]: false })
            } else {
                setSlectedImage({ ...selectedImage, [image2]: !selectedImage[image2] })
            }

        } else {

            setShowModal(true)
            const i = index + index + 1
            setInitialSlide(i)

        }

    }

    const handleTopImageClick = function (index, image1) {
        if (hideImages) {
            if (selectedImage[image1]) {
                const arr = [selectedImage]
                arr.splice(selectedImage[image1])
                setSlectedImage(arr)
            } else {
                setSlectedImage({ ...selectedImage, [image1]: !selectedImage[image1]})
            }
        } else {
            setShowModal(true)
            const i = index + index
            setInitialSlide(i)
        }
    }


    return (
        <>
            {hideImages ? (

                <div className="ion-padding" style={{ textAlign: "center" }}>
                    <IonLabel position="stacked"> Select the images you want to hide from the customer view. Tap finished when done. </IonLabel>
                    <br /><br />
                    <div style={{ justifyContent: 'center', display: "flex" }}>
                        <IonButton onClick={() => console.log(selectedImage)} size="small">
                            Finished
                    </IonButton>
                    </div>
                    <br />
                </div>

            ) : (
                    null
                )}
            <div style={{ justifyContent: 'center', display: "flex" }}>

                <Slider className="image-slider-frame" asNavFor={nav1} ref={slider => (slider1.current = slider)} {...settings}>
                    {chunk(images, 2).map(([image1, image2], i) =>

                        <ul className="listing-image-slidee" key={i}>

                            <div>
                                <li className="listing-image-pairs">
                                    <img onClick={() => {handleTopImageClick(i, image1);} } height="206px" width="272px" className="img" src={image1} />
                                    <IonIcon onClick={() => handleTopImageClick(i, image1)} className="image-hide" key={image1} size="large" hidden={selectedImage[image1] ? false : true} icon={eyeOffOutline} />
                                </li>
                            </div>

                            <div >
                                {image2 && <li className="listing-image-pairs">
                                    <img onClick={() => handleBottomImageClick(i, image2)} height="206px" width="272px" className="img" src={image2} />
                                    <IonIcon className="image-hide" key={image2} size="large" onClick={() => handleBottomImageClick(i, image2)} hidden={selectedImage[image2] ? false : true} icon={eyeOffOutline} />
                                </li>}
                            </div>

                        </ul>

                    )}
                </Slider>

            </div>
            <div>

                <Modal ariaHideApp={false} className="Modal" isOpen={showModal}>
                    <IonGrid>
                        <IonRow clasName="ion-no-padding" style={{ justifyContent: 'center' }} >
                            <IonCol sizeXs="13" sizeSm="13" sizeMd="9" sizeLg="7" sizeXl="7" >
                                <Slider style={{ maxHeight: "768px" }} asNavFor={nav2} ref={slider => (slider2.current = slider)}  {...viewSettings}>
                                    {(images).map((image, i) =>
                                        <div>
                                            <br />
                                            <img src={image} />
                                        </div>

                                    )}
                                </Slider>
                                <br/>
                                <IonItem lines="none">
                                    <IonButton size="small" color="secondary" slot="end" onClick={() => setShowModal(false)}>close</IonButton>
                                </IonItem>
                            </IonCol>
                        </IonRow>
                    </IonGrid>
                </Modal>

            </div>
        </>
    )
}
export default SliderComponent;

Ответы [ 4 ]

4 голосов
/ 01 июня 2020

Вы не должны использовать splice или pop для удаления элемента из массива, потому что это напрямую изменяет состояние реакции. Вы можете использовать функцию filter, чтобы удалить этот элемент. Функция фильтра возвращает новый массив без изменения исходного.

const newArr = selectedImage.filter(item => item !== image1);
setSelectedImage(newArr);
2 голосов
/ 29 мая 2020

Прежде всего, вы должны инициализировать selectedImage с помощью object, а не массивом, поскольку это то, что вы ожидаете от него позже

Во-вторых, предполагая, что это объект, вы не будете использовать splice в теме. Вы должны либо удалить ключ, либо сделать его ложным.

В любом случае вы должны убедиться, что вы клонируете объект перед обновлением в состоянии

const [selectedImage, setSlectedImage] = useState({}); // Initialize object
...
const handleTopImageClick = function (index, image1) {
    if (hideImages) {
        if (selectedImage[image1]) {
            setSlectedImage({...selectedImage, [image1]: false}); // hide image
        } else {
            setSlectedImage({ ...selectedImage, [image1]: true}); // show
        }
    } else {
        setShowModal(true)
        const i = index + index
        setInitialSlide(i)
    }
}
0 голосов
/ 04 июня 2020

предположим, что у нас есть массив images, содержащий все изображения. И пусть hiddenImages будет массивом, который будет содержать все изображения, которые мы хотим скрыть при нажатии. Затем функция hideImage() может быть вызвана с параметром imageId, который может быть запущен onClick кнопки. Затем функция отфильтрует изображение с соответствующим идентификатором изображения и добавит его в массив hiddenImages, а также удалит изображение из массива images путем объединения массива по индексу выбранного изображения, как показано ниже.

function Carousel(props) {
  let images = [
    {
      id: 321,
      url: "",
    },
    {
      id: 322,
      url: "",
    },
  ];

  let hiddenImages = [];

  let hideImage = (imageId) => {
    hiddenImages = [
      ...hiddenImages,
      ...images.filter((item) => item.id == imageId),
    ];
    let index;
    images.map((image) => {
      if (image.id == imageId) {
        index = images.indexOf(image);
        return;
      }
    });
    images.splice(index, 1);
  };

  return (
    <div>
      {images && images.length
        ? images.map((image, key) => {
            return (
              <img key={key} src={image.url} onClick={hideImage(image.id)} />
            );
          })
        : null}
    </div>
  );
}

0 голосов
/ 28 мая 2020

setSelectedImage(prevImages => {
  const index = prevImages.indexOf(image1);
  return [...prevImages.slice(0, index), ...prevImages.slice(index+1)];
});

Идея в том, чтобы найти индекс элемента в списке. Когда вы знаете его положение, вы можете вернуть новый массив, в котором вы распределите существующий от начала до индекса, а затем от индекса + 1 до конца. Это не изменит существующий объект-состояние.

Кроме того, при установке состояния на основе предыдущего состояния безопаснее всего использовать функцию обратного вызова свойства установки состояния. Не гарантируется, что get'er, полученный от useState, будет самым последним и лучшим, когда произойдет изменение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...