首页 > 解决方案 > Virtual Swiper 无法与 React Hook 一起使用

问题描述

我想要虚拟 swiperreact hooks工作。我这样做是为了从 api 更新更多数据。

我正在使用两个包:

"react-id-swiper": "^3.0.0",,

"swiper": "^5.3.6",

"react": "^16.11.0"

api 文档中的示例:https ://swiperjs.com/api/#virtual 。

我不能renderExternal在反应钩子中使用具有功能的虚拟刷卡器。虽然,我已经尝试过使用它。

我的代码使用effect: 'coverflow',

import React, { useEffect, useState } from 'react';
import { makeStyles } from '@material-ui/styles';
import './CoverflowShow.scss';
import PropTypes from 'prop-types';
import { useHistory, useParams } from 'react-router';
import { Tooltip } from '@material-ui/core';
import Swiper from 'react-id-swiper';

const useStyles = makeStyles((theme) => ({
  tooltipPlacementBottom: {
    margin: theme.spacing(1, 0)
  },
  tooltipPlacementTop: {
    margin: theme.spacing(1, 0)
  },
  tooltip: {
    backgroundColor: theme.palette.color.main,
    opacity: '0.9 !important'
  },
  arrow: {
    color: theme.palette.color.main
  }
}));

const CoverflowShow = React.memo(({
  files, styleCoordinates, foods, resetState, size, removeAddnewTranslation
}) => {
  const classes = useStyles();
  const [coverflowSwiper, getCoverflowSwiper] = useState(null);
  const history = useHistory();
  const params = useParams();
  const [state, setState] = useState({
    // dummy slides data
    slides: files,
    // virtual data
    virtualData: {
      slides: []
    }
  });

  /**
   * @function getInitialSlide
   * @description get initial slide
   * @returns {Number} of initialSlide
   */
  const getInitialSlide = () => {
    if (files.length > 1 && params.menu_id) {
      const menuId = parseInt(params.menu_id, 0);
      return files.findIndex((f) => f.id === menuId);
    }
    return 0;
  };

  /**
   * @description params of Coverflow Effect
   */
  const CoverflowEffect = {
    getSwiper: getCoverflowSwiper,
    effect: 'coverflow',
    initialSlide: getInitialSlide(),
    // simulateTouch: false,
    centeredSlides: true,
    slidesPerView: 'auto',
    coverflowEffect: {
      rotate: 50,
      stretch: 0,
      depth: 100,
      modifier: 1,
      slideShadows: true
    },
    navigation: {
      nextEl: '.swiper-button-next',
      prevEl: '.swiper-button-prev',
    },
    // virtual: {
    //   slides: state.slides,
    // renderExternal(data) {
    //   setState({ ...state, virtualData: data });
    // }
    // },
  };

  useEffect(() => {
    /**
     * @function handleSlideChanged
     * @description handle slide changed
     * @param {object} is swiper
     * @returns {Number|String}
     */
    const handleSlideChanged = (swiper) => {
      if (files.length > 1) {
        const file = files[swiper.activeIndex];
        resetState();
        return history.push({
          pathname: `/menus/${file.id}`,
          search: file.current_page ? `?page=${file.current_page}` : null
        });
      }
      return 0;
    };

    if (coverflowSwiper !== null) {
      coverflowSwiper.virtual.slides = state.slides;
      coverflowSwiper.virtual.renderExternal = (data) => setState({ ...state, virtualData: data });
      coverflowSwiper.on('slideChange', () => handleSlideChanged(coverflowSwiper));
    }

    return () => {
      if (coverflowSwiper !== null) {
        coverflowSwiper.off('slideChange', () => handleSlideChanged(coverflowSwiper));
      }
    };
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [coverflowSwiper, history, state]);

  /**
   * @function handleOnclickFood
   * @description handle onclick food and redirect food by id
   */
  const handleOnclickFood = (item) => () => {
    removeAddnewTranslation();
    const path = `${window.location.pathname}`;
    const pushStateURL = `${path}?foods=${item.id}`;
    history.push(pushStateURL);
  };

  const coordinateOfFoods = foods.map((food) => (
      <div
        style={{
          position: 'absolute',
          height: 10,
          width: 10,
          borderRadius: 10,
          backgroundColor: '#dd4242',
          border: '1px solid #fff',
          transform: 'translate(-6px, -6px)',
          cursor: 'pointer'
        }}
        className="coordinateSlide"
        onClick={handleOnclickFood(food)}
      />
  ));
 
  // Render list slides has background image
  const backgroundImage = state.slides.map((file) => (
  // const backgroundImage = files.slides.map((file) => (
  // const backgroundImage = state.virtualData.slides.map((file) => (
    <div
      key={file.id}
      style={{
        backgroundImage: `url(${file.photo})`,
        backgroundSize: 'contain',
        backgroundRepeat: 'no-repeat'
      }}
    >
      {coordinateOfFoods}
      <div style={styleCoordinates} className="coordinateSlide" />
    </div>
  ));

  return (
    <div className="Coverflow-effect-show">
      <Swiper {...CoverflowEffect}>
        {backgroundImage}
      </Swiper>
    </div>
  );
});

CoverflowShow.propTypes = {
  files: PropTypes.array,
  foods: PropTypes.array,
  coordinates: PropTypes.object,
  styleCoordinates: PropTypes.object,
  size: PropTypes.object,
  resetState: PropTypes.func,
  removeAddnewTranslation: PropTypes.func
};

export default CoverflowShow;

标签: reactjsswipeswiperjs

解决方案


推荐阅读