Search code examples
reactjstypescriptsharepoint-onlineslick.jsspfx

React Slick prev and next methods throw an error


import * as React from 'react';
import styles from './Birthday.module.scss';
import { IBirthdayProps } from './IBirthdayProps';
import { Icon } from 'office-ui-fabric-react/lib/Icon';
import { initializeIcons } from '@uifabric/icons';
initializeIcons();

import Slider from 'react-slick';

export default class Birthday extends React.Component<IBirthdayProps, {}> {


  public next() {
    this.slider.slickNext();
  }
  public previous() {
    this.slider.slickPrev();
  }

  public render(): React.ReactElement<IBirthdayProps> {
    const settings = {
      dots: true,
      infinite: true,
      rows: 2,
      slidesPerRow: 2,
      slidesToShow: 1,
      speed: 500,
      appendDots: dots => (
        <div
          style={{
            backgroundColor: '#ddd',
            padding: '5px',
            display: 'flex'
          }}
        >
          <ul style={{ margin: '0px', padding: '0px' }}> {dots} </ul>
        </div>
      )
    };
    return (
      <div className={styles.wrapper}>
        <Slider ref={slider => (this.slider = slider)} {...settings}>
          <div className={styles.item}>
            <h3>1</h3>
          </div>
          <div className={styles.item}>
            <h3>2</h3>
          </div>
          <div className={styles.item}>
            <h3>3</h3>
          </div>
          <div className={styles.item}>
            <h3>4</h3>
          </div>
          <div className={styles.item}>
            <h3>5</h3>
          </div>
        </Slider>
        <div style={{ display: 'flex', padding: '30px', marginTop: '30px' }}>
          <Icon
            iconName="ChevronLeftSmall"
            className={styles.customArrow}
            onClick={this.next}
          />
          <Icon
            iconName="ChevronRightSmall"
            className={styles.customArrow}
            onClick={this.previous}
          />
        </div>
      </div>
    );
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

I'm trying to make use of the react slick carousel. I tried to customized it a bit so I created next and prev button which should trigger the carousel's method for next and previous. To be clear I'm developing in SPFX, which is SharePoint framework, React with Typescript. I get the following error as the code is written:(same for this.slider inside Slider Component)

enter image description here

I developed by the their docs here: https://react-slick.neostack.com/docs/example/previous-next-methods I've tried creating variables as slide and slider and add them as props or as state or just a variable inside my class but it didn't succeed..

I expect the buttons to trigger the next and prev methods...

Appreciate any help!


Solution

  • Sample demo:

    import * as React from 'react';
    import styles from './ReactSpFx.module.scss';
    import { IReactSpFxProps } from './IReactSpFxProps';
    import { escape } from '@microsoft/sp-lodash-subset';
    
    import { SPHttpClient, SPHttpClientResponse, SPHttpClientConfiguration } from '@microsoft/sp-http';
    
    import Slider from "react-slick";
    import "../../../../node_modules/slick-carousel/slick/slick.css"; 
    import "../../../../node_modules/slick-carousel/slick/slick-theme.css";
    import { any } from 'prop-types';
    
    export interface IReactItem{ 
      ID:string,
      Title:string,
      Address:string
    }
    
    export interface IReactGetItemsState{ 
      items:IReactItem[]
    }
    
    export default class ReactSpFx extends React.Component<IReactSpFxProps,IReactGetItemsState> {
    
      public constructor(props: IReactSpFxProps) {
        super(props);
        this.state = {
          items:[]   
        };
        this.next = this.next.bind(this);
        this.previous = this.previous.bind(this);    
      }
    
    
      public componentDidMount() {
        var reactHandler = this;
        this.props.context.spHttpClient.get(`${this.props.context.pageContext.web.absoluteUrl}/_api/web/lists/getbytitle('TestList')/items?select=ID,Title,Address`,
        SPHttpClient.configurations.v1) .then((response: SPHttpClientResponse) => {  
          response.json().then((responseJSON: any) => {            
            reactHandler.setState({
              items: responseJSON.value
            });
          });  
        });   
      }
    
      protected slider;
      next() {
        this.slider.slickNext();
      }
      previous() {
        this.slider.slickPrev();
      }
    
      public render(): React.ReactElement<IReactSpFxProps> {
        const settings = {
          dots: true,
          infinite: true,
          speed: 500,
          slidesToShow: 1,
          slidesToScroll: 1
        };
        return (
          <div className={styles.reactSpFx}>
            <div className={styles.container}>  
            {(this.state.items || []).map(item => (
                <div key={item.ID} className={styles.row}>{item.Title}
                <div dangerouslySetInnerHTML={{ __html: item.Address.replace(/[\n\r]/g,"<br/>")}}></div> 
              </div> 
              ))}                          
            </div>
            <div>
              <h2> Single Item</h2>
              <Slider ref={c => (this.slider = c)} {...settings}>
                <div>
                  <h3>1</h3>
                </div>
                <div>
                  <h3>2</h3>
                </div>
                <div>
                  <h3>3</h3>
                </div>
                <div>
                  <h3>4</h3>
                </div>
                <div>
                  <h3>5</h3>
                </div>
                <div>
                  <h3>6</h3>
                </div>
              </Slider>
              <br/>
              <div style={{ textAlign: "center" }}>
              <button className="button" onClick={this.previous}>
                Previous
              </button>
              <button className="button" onClick={this.next}>
                Next
              </button>
            </div>
            </div>
          </div>      
        );    
      }
    }
    

    Suppose you mean IReactSpFxProps

    import { WebPartContext } from '@microsoft/sp-webpart-base';
    export interface IReactSpFxProps {
      description: string,
      context: WebPartContext;
    }