React-id-swiper: Link tags in React Router acting as normal anchor tags in loop mode

Created on 24 Jan 2018  路  9Comments  路  Source: kidjp85/react-id-swiper

In loop mode, the "duplicate" slides that have Link tags (from React Router)behave as normal anchor tags and reload the full page when clicked on. Normal swiper slides (non duplicates) act as the Link tags should.

I'm on Swiper version: 1.5.6. Thanks :)

Discussion bug

All 9 comments

I can confirm that upon further testing, it's not just Link tags. It's also libraries like react-truncate, for example, that have their tags ignored.

Any update on this?

Hi @JoshMoxey , sorry for my late reply. It will be really helpful if u can share ur code . Thank you

I experienced a potentially similar problem where I had JSX with event listeners which didn't work in the duplicate slides.

same issue when loop: true
reproduce CodeSandbox

Apologies for the delay on my end too. Thankfully it seems @SaeedSheikhi has reproduced what I'm referring to. The extra slides that create the simulated loop effect aren't behaving as Link tags, but instead as anchor tags.

Thanks for the great plugin.

I can confirm this is reproducible.
When you check in React devtools extension, only original set of slides are present.
It seems like duplicate slides are just being created by swiper library.

Hi folks, sorry for my late response. So busy recently. In loop mode Swiper duplicates first and last slides , and events are not copied, so any event bound is invalid. That why <Link /> tag won't work as expected.

I made a quick fix here here . To be honest, I don't want to do in this way, but Swiper has limitation in loop mode.

My solutions for this issue:

  1. Make swiper ref
  2. Replace Link with HOC withRouter to use history.push
  3. In componentDidUpdate, add click event for duplicated slides
import React from "react";
import { render } from "react-dom";
import { BrowserRouter as Router, Route, withRouter } from "react-router-dom";
import {
  compose,
  withHandlers,
  withProps,
  withState,
  lifecycle
} from "recompose";
import Hello from "./Hello";
import Swiper from "react-id-swiper";

const styles = {
  fontFamily: "sans-serif",
  textAlign: "center"
};

const params = {
  loop: true,
  slidesPerView: 1.5,
  spaceBetween: 30,
  freeMode: true,
  grabCursor: true,
  centeredSlides: true
};

const Slider = compose(
  withRouter, // Use `withRouter` HOC to use `props.history`
  withState("swiper", "toggleSwiper", null), // Add swiper props
  withProps(props => ({
    // Generate demo data
    items: [...Array(5).keys()].map(idx => ({
      link: `test${idx + 1}`,
      name: `Slide ${idx + 1}`
    }))
  })),
  withHandlers({
    swiperRef: ({ toggleSwiper }) => ref => {
      //Swiper ref
      if (ref) {
        toggleSwiper(ref.swiper);
      }
    },
    // User history push instead of `Link` component from `react-router-dom`
    redirectPath: ({ history }) => item => () => {
      // Redirect method - Should be a curry function
      history.push(item.link);
    }
  }),
  withHandlers({
    renderSlide: ({ redirectPath }) => (
      slide,
      idx // Render slide method
    ) => (
      <span
        key={idx}
        style={{ border: "3px solid black", padding: "15px" }}
        onClick={redirectPath(slide)}
      >
        {`slide ${idx + 1}`}
      </span>
    )
  }),
  lifecycle({
    componentDidUpdate(prevProps) {
      if (prevProps.swiper === null && this.props.swiper) {
        const { swiper, items, redirectPath } = this.props;
        const slides = swiper.slides;

        // Add click event for duplicated slides
        Array.prototype.forEach.call(slides, s => {
          if (s.classList.contains("swiper-slide-duplicate")) {
            const index = s.getAttribute("data-swiper-slide-index");
            s.onclick = redirectPath(items[index]);
          }
        });
      }
    }
  })
)(({ renderSlide, items, swiperRef }) => (
  <Swiper ref={swiperRef} {...params}>
    {items.map(renderSlide)}
  </Swiper>
));

const App = ({ renderSlide }) => (
  <div style={styles}>
    <Hello name="CodeSandbox" />
    <Router>
      <div>
        <Route
          exact
          path="/test1"
          render={props => <div>Test 1 content</div>}
        />
        <Route
          exact
          path="/test2"
          render={props => <div>Test 2 content</div>}
        />
        <Route
          exact
          path="/test3"
          render={props => <div>Test 3 content</div>}
        />
        <Route
          exact
          path="/test4"
          render={props => <div>Test 4 content</div>}
        />
        <Route
          exact
          path="/test5"
          render={props => <div>Test 5 content</div>}
        />
        <Route exact path="/" render={Slider} />
      </div>
    </Router>
  </div>
);

render(<App />, document.getElementById("root"));

PS: I wrote this with recompose, if u guys have any question , feel free to ask.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

d4n1b picture d4n1b  路  5Comments

Pixel-Daze picture Pixel-Daze  路  4Comments

catamphetamine picture catamphetamine  路  5Comments

Fenopiu picture Fenopiu  路  3Comments

thientran1707 picture thientran1707  路  3Comments