为什么 debounce 不调用我的函数?

Why debounce doesnt invoke my function?

我正在使用 Reactmobx.

做一些事情

我创建了一个 ImageCarousel 组件,我在其中显示了被单击的图像。 我有一个 previous 和一个 next 按钮(它们本身就是一个组件),用于在图像之间移动。

我试图用 lodash debounce 包装那些动作(prevnext), 但途中出现问题。

我当前的商店有那些操作:

debounceAction 只是一个高阶函数,它获取 2 个参数(fn,等待),并使用这些参数调用 lodash debounce

我的 CarouselButton 组件通过它的道具获得我上面提到的那些动作。在组件内部,我使用 onClick 事件触发以使用实际操作调用 debounceAction(fn, wait)prev,或 next)。

我不确定如何以正确的方式用去抖来包装我的动作。

我在第二个代码片段(在 CarouselButton 组件 中)调用 debounceAction(包装去抖动的 HOF) .

你看到我这里的错误了吗?

galleryStore.jsx - 当前商店:

class GalleryStore {

    // Observables    
    @observable images = [
        // ....images
    ];

    @observable carouselleButtons= {
        next: "fa fa-chevron-right",
        back: "fa fa-chevron-left"
    }
    @observable selectedImageIndex = null;
    @observable hideCarousel = true;
    @observable onTransition = false;

  // Actions
    selectImage = (index) =>{
        this.selectedImageIndex = index;
    }

    toggleCarousel = () =>{
        this.hideCarousel = !this.hideCarousel;
    }

    carouselNext = () => {
        if(this.selectedImageIndex == this.images.length - 1) {
            return;
        }

        this.onTransition = true;
        setTimeout(() => {
            this.selectedImageIndex = this.selectedImageIndex + 1;
            this.onTransition = false;
        },500)
    }

    carouselPrev = () => {
        if(this.selectedImageIndex == 0) {
            console.log('start of the collection');          
            return;
        } 

        this.onTransition = true; 
        setTimeout(() => {
            this.selectedImageIndex = this.selectedImageIndex - 1;
            this.onTransition = false;        
        }, 500)       
    }

    debounceAction = (fn, wait) => {
        //lodash's debounce
        return debounce(fn, wait);
    }

carouselButton 组件 - 这里我调用 debounce:

// React's
import React from 'react';

// Styles
import CarouselButtonStyle from './carouselButtonStyle';

// CarouselButton Component
export default class CarouselButton extends React.Component {
    debounce = (e) =>{
        const { debounceAction } = this.props;

        // ----->    HERE I CALL DEBOUNCE !   <---------
        e.stopPropagation();
        debounceAction(this.buttonHandler, 400);
    }

    buttonHandler = (e) => {
        const {limit, index, action, debounceAction} = this.props;

        if(index == limit)  return;
        else action();
    }

    render(){
        const {limit, index, icon, action, debounceAction} = this.props;

        return(
            <CarouselButtonStyle 
                onClick={(e) => {this.debounce(e)}} 
                className={ index == limit ? 'end-of-collection' : '' } >

                <i className={icon} aria-hidden="true" />
            </CarouselButtonStyle>
        );
    }
}

imageCarousel.jsx - carouselButton parent 组件:

// React's
import React from 'react';

// Mobx-react's
import { observer, inject } from 'mobx-react';

// Styles
import ImageCarouselStyle from './imageCarouselStyle';

// Components
import ImgContainer from './imgContainer/imgContainer';
import CarouselButton from './carouselButton/carouselButton';

// ImageCarousel Component
@inject('galleryStore')
@observer
export default class ImageCarousel extends React.Component {
    closeCarousel = () => {
        this.props.galleryStore.toggleCarousel();
    }

    onKeyDown = (e) => {
        const { keyCode } = e;

        if(keyCode ===27) this.onEscHandler();
        else if (keyCode == 37) this.onLeftArrow();
        else if (keyCode == 39) this.onRightArrow();
        else return;
    }

    onLeftArrow = () => { this.props.galleryStore.carouselPrev()  }

    onRightArrow = () => { this.props.galleryStore.carouselNext() }

    onEscHandler = () => { this.closeCarousel() }

    componentDidMount(){
        document.addEventListener('keydown', this.onKeyDown, false);
    }

    render(){
        return(
            <ImageCarouselStyle 
                hidden={this.props.galleryStore.hideCarousel}
                onClick={this.closeCarousel} >

                <CarouselButton action={'prev'} 
                    icon={this.props.galleryStore.carouselleButtons.back} 
                    action={this.props.galleryStore.carouselPrev}
                    limit={0}
                    index={this.props.galleryStore.selectedImageIndex} 
                    debounceAction={this.props.galleryStore.debounceAction} />

                <ImgContainer 
                    images={this.props.galleryStore.images} 
                    imgIndex={this.props.galleryStore.selectedImageIndex} 
                    onTransition={this.props.galleryStore.onTransition}/>

                <CarouselButton action={'next'} 
                    icon={this.props.galleryStore.carouselleButtons.next} 
                    action={this.props.galleryStore.carouselNext} 
                    limit={this.props.galleryStore.amountOfImages}
                    index={this.props.galleryStore.selectedImageIndex} 
                    debounceAction={this.props.galleryStore.debounceAction} /> 

            </ImageCarouselStyle>
        );
    }
}

问题是您必须从 CarouselButtondebounce 方法 return debounceAction

debounce = (e) =>{
    const { debounceAction } = this.props;

    // ----->    HERE I CALL DEBOUNCE !   <---------
    e.stopPropagation();
    debounceAction(this.buttonHandler, 400);
// -^^^ must return here
}

但是,我建议更进一步以避免将来出现混淆。只需在需要时调用 lodash 的 debounce,而不是在代码中多次重写它并导致有问题的方法名称。

下面是如何包装点击处理程序的最基本示例:

class Button extends React.Component {
  handleClick = _.debounce((e) => {
    alert('debounced click reaction')
  }, 1000)

  render() {
    return <button onClick={this.handleClick}>CLICK ME</button>
  }
}

ReactDOM.render(
  <Button />,
  document.getElementById('app')
);
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>