Usr
Usr

Reputation: 2838

react change slide in slider after clicking a button

I have a Sidebar that I've implemented this way:

import React from "react";
import './MySidebar.scss';
import {slide as Menu } from 'react-burger-menu'

export class MySidebar extends React.Component {


  constructor(props) {
    super(props);
  }


 changeSlide = (e) => {
   console.log("Clicked " + e.currentTarget.id); //get text content of
 }


  render() {


    return (
        <Menu customCrossIcon={false}>
            <button onClick={((e) => this.changeSlide(e))} className ="menu-item" id="Project1">Project 1</button>
      <button onClick={((e) => this.changeSlide(e))} className ="menu-item" id="Project2">Project 2</button>
        </Menu>
    );
  }
} 

Then I have a component called ProjectSliderComponent that realizes the behaviour of a carousel. It is done this way:

import React from "react";
import Slider from "react-slick";
import './project-carousel.component.css';
import { ProjectComponent } from '../project/project.component';
import { LoggerService } from '../../services/logger-service';
import { appConfig } from '../../config';

export class ProjectSliderComponent extends React.Component {

  state = {
    activeSlide: 0,
    timestamp: Date.now()
  }

  constructor(props) {
    super(props);
    this.logger = new LoggerService();

    this.settings = {
      dots: appConfig.dots,
      arrows: false,
      adaptiveHeight: true,
      infinite: appConfig.infinite,
      speed: appConfig.speed,
      autoplay: appConfig.autoplay,
      autoplaySpeed: appConfig.autoplaySpeed,
      slidesToShow: 1,
      slidesToScroll: 1,
      mobileFirst: true,
      className: 'heliosSlide',
      beforeChange: (current, next) => {
        this.setState({ activeSlide: next, timestamp: Date.now() }); 
      }
    };
  }

  render() {

    let i = 0;

    return (
      <div>
      <Slider ref = {c => (this.slider = c)} {...this.settings}>
        {
          this.props.projectListId.data.map(projectId =>
              <ProjectComponent key={projectId} id={projectId} time={this.state.timestamp} originalIndex={ i++ } currentIndex = {this.state.activeSlide}></ProjectComponent>)
        }
      </Slider>
      </div>
    );
  }
}

The ProjectComponent component simply specifies the layout. This is the App.js file, where I load the projectslidercomponent and my sidebar. I do this:

class App extends Component {

  state = {
    projectList: new ProjectListModel(),
    isLoading: true
  }

  constructor(props) {
    super(props);
    this.logger = new LoggerService();
  }



  componentDidMount() {
    let projectService = new ProjectService();
    projectService.getProjectList()
      .then(res => {
        let projectList = new ProjectListModel();
        projectList.data = res.data.data;
        this.setState({ projectList: projectList,
                        isLoading: false });
      })
      .catch(error => {
        this.logger.error(error);
      });
  }



  render() {
      return (
        <div className="App">
          <MySidebar>
            </MySidebar>
          <ProjectSliderComponent projectListId={this.state.projectList}></ProjectSliderComponent>
        </div>
      );
    }
}

export default App;

What I need to do is to change the slide according to which button I clicked. What do I have to do? Is there something like passing the "instance" of the projectslidercomponent and call a method to change the slide? Or something else?

Upvotes: 0

Views: 6730

Answers (2)

Codesingh
Codesingh

Reputation: 3384

To sort this problem what you have to do is create a function in parent component which updates the state of the app component and once the state is updated it will re render app component and the new props are send to slider component which will tell which slider to show. Below is the code :-

In App.js

class App extends Component {

  state = {
    projectList: new ProjectListModel(),
    isLoading: true,
    menuId: 0
  }

  constructor(props) {
    super(props);
    this.logger = new LoggerService();
  }



  componentDidMount() {
    let projectService = new ProjectService();
    projectService.getProjectList()
      .then(res => {
        let projectList = new ProjectListModel();
        projectList.data = res.data.data;
        this.setState({ projectList: projectList,
                        isLoading: false });
      })
      .catch(error => {
        this.logger.error(error);
      });
  }

  ChangeSlide = (menuId) => {
   this.setState({
      menuId //Here you will receive which slide to show and according to that render slides in mySliderbar component
   })
  }



  render() {
      return (
        <div className="App">
          <MySidebar ChangeSlide={this.ChangeSlide} />
          <ProjectSliderComponent menuId={this.state.menuId} projectListId={this.state.projectList}></ProjectSliderComponent>
        </div>
      );
    }
}

export default App;

In mySlidebar

import React from "react";
import './MySidebar.scss';
import {slide as Menu } from 'react-burger-menu'

export class MySidebar extends React.Component {


  constructor(props) {
    super(props);
  }


 changeSlide = (e) => {
   console.log("Clicked " + e.currentTarget.id); //get text content of
   this.props.changeSlide(e.currentTarget.id)
 }


  render() {


    return (
        <Menu customCrossIcon={false}>
            <button onClick={((e) => this.changeSlide(e))} className ="menu-item" id="Project1">Project 1</button>
      <button onClick={((e) => this.changeSlide(e))} className ="menu-item" id="Project2">Project 2</button>
        </Menu>
    );
  }
} 

In slider component, you have to listen when the new props are coming and according to that change the slide see componentWillReceiveProps

import React from "react";
import Slider from "react-slick";
import './project-carousel.component.css';
import { ProjectComponent } from '../project/project.component';
import { LoggerService } from '../../services/logger-service';
import { appConfig } from '../../config';

export class ProjectSliderComponent extends React.Component {

  state = {
    activeSlide: 0,
    timestamp: Date.now()
  }

  constructor(props) {
    super(props);
    this.logger = new LoggerService();

    this.settings = {
      dots: appConfig.dots,
      arrows: false,
      adaptiveHeight: true,
      infinite: appConfig.infinite,
      speed: appConfig.speed,
      autoplay: appConfig.autoplay,
      autoplaySpeed: appConfig.autoplaySpeed,
      slidesToShow: 1,
      slidesToScroll: 1,
      mobileFirst: true,
      className: 'heliosSlide',
      beforeChange: (current, next) => {
        this.setState({ activeSlide: next, timestamp: Date.now() }); 
      }
    };
  }
  componentWillReceiveProps(nextProps) {
   if(nextprops.menuId != this.props.menuId){
    this.slider.slickGoTo(nextprops.menuId, true)//use slider instance to 
    //call the function to go to a particular slide.
   }
  }


  render() {

    let i = 0;
    const { menuId } = this.props
    return (
      <div>
      <Slider initialSlide={menuId} ref = {c => (this.slider = c)} {...this.settings}>
        {
          this.props.projectListId.data.map(projectId =>
              <ProjectComponent key={projectId} id={projectId} time={this.state.timestamp} originalIndex={ i++ } currentIndex = {this.state.activeSlide}></ProjectComponent>)
        }
      </Slider>
      </div>
    );
  }
}

Upvotes: 1

Bj&#246;rn Hei&#223;
Bj&#246;rn Hei&#223;

Reputation: 1728

At the react-slick docs you can read about slickGoTo, which is a method of the Slider component.

Since you're already storing this.slider you can try to make it accessible in MySidebar and use it whenever changeSlide is called. Most likely you have to create a changeSlide method on top level and hand it as property to your components.

Upvotes: 2

Related Questions