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

时间:2017-11-29 12:59:53

标签: javascript reactjs lodash mobx debounce

我正在开展 React mobx 的工作。

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

我尝试用lodash debounce包装这些操作(上一页下一页), 但是在途中失败了。

我现在的商店有这些行动:

  • prevCarousel
  • nextCarousel
  • debounceAction

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

我的CarouselButton组件通过它支持我上面提到的那些动作。在我使用onClick事件触发的组件内部,以实际操作(上一步下一步)调用debounceAction(fn, wait)

我不确定如何用正确的方式去辩护。

我在第二个代码段(在 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 Component - 在这里我调用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>
        );
    }
}

1 个答案:

答案 0 :(得分:1)

问题是您必须从debounceAction CarouselButton方法返回debounce

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

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

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

以下是如何打包单击处理程序的最基本示例:

&#13;
&#13;
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')
);
&#13;
<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>
&#13;
&#13;
&#13;