1

I am stuck on an issue with my SlideShow with Redux , which I am new with. I am trying to figure out the logic to connect my dropdown select and the next and previous buttons so that redux keeps track of my state. I want the user to be able to navigate through the slides, and also be able to select a slide from the dropdown. I cant figure out what I should do to connect it all but i think i'm close... :\

My Slides

const SlideData = [
  {
    title: "Introduction",
    content: "This is some content",
  },
  {
    title: "Slide 2",
    content: "This is some content",
  },
  {
    title: "Slide 3",
    content: "This is some content",
  },
  {
    title: "Slide 4",
    content: "This is some content",
  },
];

export default SlideData;

REDUX FILE

import { createSlice, configureStore } from "@reduxjs/toolkit";
import SlideData from "../SlideData";

//SET INITIAL STATE//
const initialSlideState = {
  SlideData,
  totalSlides: SlideData.length,
  currentSlide: 0,
  progress: 0,
};

//SET REDUCERS//
const slideSlice = createSlice({
  name: "slide",
  initialState: initialSlideState,
  reducers: {
    setCurrentSlide(state, action) {
      state.currentSlide = SlideData[action.payload];
    },
    nextSlide(state) {
      if (state.currentSlide < state.totalSlides) {
        state.currentSlide++;
      }
    },
    prevSlide(state) {
      if (state.currentSlide > 0) {
        state.currentSlide--;
      }
    },
    setProgress(state, action) {
      state.progress = action.payload;
    },
  },
});

//CREATE STORE//
const store = configureStore({
  reducer: slideSlice.reducer,
});

export const slideActions = slideSlice.actions;
export default store;

SLIDESHOW FILE

//IMPORTS//
import React, { useRef } from "react";
import styles from "./Slideshow.module.css";
import Button from "./UI/Button";
import { Slide } from "react-slideshow-image";
import SlideData from "../SlideData";
import { useSelector, useDispatch } from "react-redux";
import { slideActions } from "../store/index";
import "react-slideshow-image/dist/styles.css";


export default function Slideshow() {
  const dispatch = useDispatch();
  const slideRef = useRef();
  const currentSlide = useSelector((state) => state.currentSlide);
  const totalSlides = useSelector((state) => state.totalSlides);

  //SET CURRENT SLIDE
  const setCurrentSlideHandler = (index) => {
    dispatch(slideActions.setCurrentSlide(index));
  };

  //NEXT SLIDE
  const nextSlideHandler = () => {
    dispatch(slideActions.nextSlide());
    dispatch(slideActions.setProgress((currentSlide / totalSlides) * 100));
    slideRef.current.goNext();
  };

 //PREVIOUS SLIDE
  const prevSlideHandler = () => {
    dispatch(slideActions.prevSlide());
    dispatch(slideActions.setProgress((currentSlide / totalSlides) * 100));
    slideRef.current.goBack();
  };

//GO TO SLIDE (DROPDOWN)<<--feel like i'm close here? 
  const goto = ({ target }) => {
    console.log("Before: " + currentSlide);
    let info = parseInt(target.value, 10);
    console.log(info);
    setCurrentSlideHandler(info);
    slideRef.current.goTo(currentSlide);
    console.log("after: " + currentSlide);
  };

  //SLIDESHOW PROPS//
  const properties = {
    transitionDuration: 200,
    autoplay: false,
    arrows: false,
  };

  //MAP DATA FOR DROPDOWN//
  const options = SlideData.map((item, index) => (
    <option key={index} value={index}>
      {item.title}
    </option>
  ));

  return (
    <div className={styles.container}>
      <Slide ref={slideRef} {...properties}>
        {SlideData.map((item, index) => (
          <div key={index} className={styles.slide}>
            <h2>{item.title}</h2>
            <p>{item.content}</p>
          </div>
        ))}
      </Slide>
      <div>
        <Button type="button" onClick={prevSlideHandler}>
          Back
        </Button>
        <Button type="button" onClick={nextSlideHandler}>
          Next
        </Button>
        <select className={styles.select} onChange={goto}>
          <option>--Select--</option>
          {options}
        </select>
      </div>
    </div>
  );
}

PREVIEWPreview

lache
  • 608
  • 2
  • 12
  • 29
  • I am using this https://www.npmjs.com/package/react-slideshow-image btw – lache Aug 02 '21 at 20:05
  • What exactly is not working here? Any errors? – BryanOfEarth Aug 04 '21 at 20:11
  • I have a drop down and you can select a slide but it uses event target to go to the correct slide, and not thats slides index. So i guess I want to connect all of this to where there is an array of indexes(or "slides") and be able to navigate back and forth, and from the drop down menu to a specific one? as it is now It doesnt feel connected in that way or at least using state but rather using a slideref to navigate? – lache Aug 04 '21 at 20:24

1 Answers1

1

I think the problem is that in your component you are BOTH using the methods provided by the library AND trying to do things based on redux state. If you are trying to set the slides using ONLY redux, then what you want is, upon hitting the arrow to go forward or back, to dispatch the (new) "currentSlide" (index) to redux, and then use useEffect(()) to listen for changes to the currentSlide selector. When the value changes, you'll use the updated value to call the libraries method goTo(index) with that new index.

That would look like: (disclaimer: I'm removing things that don't matter to the points I'm making)

slice

import { createSlice, configureStore } from "@reduxjs/toolkit";
import SlideData from "../SlideData";

//SET INITIAL STATE//
const initialSlideState = {
  SlideData,
  totalSlides: SlideData.length,
  currentSlide: 0,
};

//SET REDUCERS//
const slideSlice = createSlice({
  name: "slide",
  initialState: initialSlideState,
  reducers: {
    setCurrentSlide(state, action) {
      state.currentSlide = action.payload;
    },
    nextSlide(state) {
      if (state.currentSlide < state.totalSlides) {
        state.currentSlide++;
      }
    },
    prevSlide(state) {
      if (state.currentSlide > 0) {
        state.currentSlide--;
      }
    },
  },
});

component

//IMPORTS//
import React, { useRef } from "react";
import styles from "./Slideshow.module.css";
import Button from "./UI/Button";
import { Slide } from "react-slideshow-image";
import SlideData from "../SlideData";
import { useSelector, useDispatch } from "react-redux";
import { slideActions } from "../store/index";
import "react-slideshow-image/dist/styles.css";


export default function Slideshow() {
  const dispatch = useDispatch();
  const slideRef = useRef();
  const currentSlide = useSelector((state) => state.currentSlide);
  const totalSlides = useSelector((state) => state.totalSlides);

  useEffect(() => {
    slideRef.current.goTo(currentSlide)
  }, currentSlide)

  //SET CURRENT SLIDE
  const setCurrentSlideHandler = (index) => {
    dispatch(slideActions.setCurrentSlide(index));
  };

  //NEXT SLIDE
  const nextSlideHandler = () => {
    dispatch(slideActions.nextSlide());
  };

  //PREVIOUS SLIDE
  const prevSlideHandler = () => {
    dispatch(slideActions.prevSlide());
  };

  //GO TO SLIDE (DROPDOWN)<<--feel like i'm close here? 
  const goto = ({ target }) => {
    let info = parseInt(target.value, 10);
    setCurrentSlideHandler(info);
  };

  //SLIDESHOW PROPS//
  const properties = {
    transitionDuration: 200,
    autoplay: false,
    arrows: false,
  };

  //MAP DATA FOR DROPDOWN//
  const options = SlideData.map((item, index) => (
    <option key={index} value={index}>
      {item.title}
    </option>
  ));

  return (
    <div className={styles.container}>
      <Slide ref={slideRef} {...properties}>
        {SlideData.map((item, index) => (
          <div key={index} className={styles.slide}>
            <h2>{item.title}</h2>
            <p>{item.content}</p>
          </div>
        ))}
      </Slide>
      <div>
        <Button type="button" onClick={prevSlideHandler}>
          Back
        </Button>
        <Button type="button" onClick={nextSlideHandler}>
          Next
        </Button>
        <select className={styles.select} onChange={goto}>
          <option>--Select--</option>
          {options}
        </select>
      </div>
    </div>
  );
}

With the above, no matter which way you go (forward, backward, or selecting explicitly), the appropriate action is dispatched and the currentSlide (INDEX) is updated in your state, from which you are getting your selector value. When the component sees that the selector value has changed, it will call the library's goTo(index) method with that value.

BryanOfEarth
  • 715
  • 11
  • 26
  • 1
    thank you for helping, I know this was a lot of code to look at! but you helped me understand. I appreciate the example too – lache Aug 05 '21 at 12:54
  • 1
    Glad to help! I'm loving Redux Toolkit, but I noticed that there is not a lot of help out there in general for it, I guess since it is so new, so I want to help all I can to support it's adoption. – BryanOfEarth Aug 05 '21 at 21:42