【问题标题】:Why debounce doesnt invoke my function?为什么 debounce 不调用我的函数?
【发布时间】:2017-11-29 12:59:52
【问题描述】:

我正在使用 Reactmobx 做一些事情。

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

我尝试使用lodash debounce 包装这些操作(prevnext), 但是途中有些事情失败了。

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

  • prevCarousel
  • nextCarousel
  • debounceAction

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

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

我不确定如何以正确的方式使用 debounce 来包装我的操作。

我在第二个代码 sn-p(在 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>
        );
    }
}

【问题讨论】:

  • 您遇到的故障是什么?是否有控制台错误?
  • @RobertFarley 我没有收到任何错误。我认为我传递给 debounce 的函数不会调用。可能是我写的不对?
  • 我不知道 React 和 mobx,但是:lodash 的 debounce 创建(并返回)一个函数,因此 debounceAction() 返回这个函数,并且在 ("HERE I CALL DEBOUNCE !") 行不使用 debounceAction() 的返回值,因此实际上没有人调用该函数。这将称之为:debounceAction(this.buttonHandler, 400)(); - 但你使用 debounce 错误:你可能不会像在你的实现中那样一次又一次地调用 debounce() ;你只需要调用 debounce() 一次,然后一次又一次地调用 debounce() 的 result
  • return debounce(action(fn), wait)

标签: javascript reactjs lodash mobx debounce


【解决方案1】:

问题是您必须从CarouselButtondebounce 方法返回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>

【讨论】:

    猜你喜欢
    • 2017-08-12
    • 2020-03-25
    • 2019-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多