React Native防止双击

时间:2016-03-23 19:28:58

标签: react-native

我有一个10/01/2000包裹TouchableHighlight块,在点击时会打开一个新场景(我使用react-native-router-flux)。
它的工作正常,但如果您快速点击Text,则场景可以渲染两次。
我想阻止用户快速点击该按钮。

在Native中实现此目的的最佳方法是什么?我查看了手势响应系统,但没有任何例子或类似的东西,如果你像我这样的新手,会让人感到困惑。

10 个答案:

答案 0 :(得分:4)

您要做的是想要限制点击回调,以便它们只运行ONCE。

这称为限制,您可以使用underscore以下是:

_.throttle(
    this.thisWillRunOnce.bind(this),
    200, // no new clicks within 200ms time window
);

这就是我的反应组件看起来的样子。

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
     _.throttle(
        this.onPressThrottledCb.bind(this),
        200, // no new clicks within 200ms time window
    );
  }
  onPressThrottledCb() {
    if (this.props.onPress) {
      this.props.onPress(); // this only runs once per 200 milliseconds
    }
  }
  render() {
    return (
      <View>
        <TouchableOpacity onPress={this.onPressThrottledCb}>
        </TouchableOpacity>
      </View>
    )
  }
}

我希望这会对你有所帮助。 如果您想了解更多信息,请查看this thread

答案 1 :(得分:2)

也许您可以使用0.22中可触摸元素引入的新禁用功能?我在想这样的事情:

<强>组件

<TouchableHighlight ref = {component => this._touchable = component}
                    onPress={() => this.yourMethod()}/>

方式

yourMethod() {
    var touchable = this._touchable;
    touchable.disabled = {true};

    //what you actually want your TouchableHighlight to do
}

我自己没有尝试过。所以我不确定它是否有效。

答案 2 :(得分:2)

我这样做:

link(link) {
        if(!this.state.disabled) {
            this.setState({disabled: true});
            // go link operation
            this.setState({disabled: false});
        }
    }
    render() {
        return (
            <TouchableHighlight onPress={() => this.link('linkName')}>
              <Text>Go link</Text>
            </TouchableHighlight>
        );
    }

答案 3 :(得分:1)

您可以在实际的接收器方法中弹出单击,尤其是在处理视觉效果的状态时。

_onRefresh() {    
    if (this.state.refreshing)
      return
    this.setState({refreshing: true});

答案 4 :(得分:1)

如果您使用react-navigation,则可以向key提供navigate属性,以确保只有一个实例添加到堆栈中。

通过https://github.com/react-navigation/react-navigation/issues/271

答案 5 :(得分:0)

我通过创建一个在传递的时间间隔内仅调用一次函数的模块来修复此错误。

示例:如果您希望从Home导航 - &gt;关于并按下“关于”按钮两次,比如400毫秒。

navigateToAbout = () => dispatch(NavigationActions.navigate({routeName: 'About'}))

const pressHandler = callOnce(navigateToAbout,400);
<TouchableOpacity onPress={pressHandler}>
 ...
</TouchableOpacity>
The module will take care that it calls navigateToAbout only once in 400 ms.

以下是NPM模块的链接:https://www.npmjs.com/package/call-once-in-interval

答案 6 :(得分:0)

在阅读了几篇github主题,SO文章并尝试了大多数解决方案后,我得出以下结论:

  1. 提供额外的key参数来执行&#34;幂等推送&#34;到目前为止并不一致。 https://github.com/react-navigation/rfcs/issues/16

  2. 使用debounce可显着降低UX的速度。导航仅在用户最后一次按下按钮后X ms发生。 X需要足够大以弥合双击可能发生的时间。这可能是真正的100-600毫秒。

  3. 使用_.throttle对我不起作用。它保存了限制函数调用,并在计时器用完后执行,导致延迟双击。

  4. 我考虑过转移到react-native-navigation,但显然问题更深层,他们也经历过这个问题。

    所以现在我构建了自己的hack,至少干扰了我的代码:

    const preventDoubleTapHack = (component: any, doFunc: Function) => {
      if (!component.wasClickedYet__ULJyRdAvrHZvRrT7) {
        //  eslint-disable-next-line no-param-reassign
        component.wasClickedYet__ULJyRdAvrHZvRrT7 = true;
        setTimeout(() => {
          //  eslint-disable-next-line no-param-reassign
          component.wasClickedYet__ULJyRdAvrHZvRrT7 = false;
        }, 700);
        doFunc();
      }
    };
    

    在任何地方,我们导航而不是

    this.props.navigation.navigate('MyRoute');
    

    DO

    preventDoubleTapHack(this, () => this.props.navigation.navigate('MyRoute');
    

    美丽。

答案 7 :(得分:0)

您可以使用去抖的非常简单的方式

DescribeInstancesPagesWithContext

答案 8 :(得分:0)

我在下面使用此lodash方法修复了

第1步

import { debounce } from 'lodash';

第2步

将此代码放入构造函数中

this.loginClick = debounce(this.loginClick .bind(this), 1000, {
            leading: true,
            trailing: false,
});

第3步

像这样在onPress按钮上写

onPress={() => this.props.skipDebounce ? this.props.loginClick : this.loginClick ()}

谢谢

答案 9 :(得分:0)

这对我来说是一种解决方法

import React from 'react';
import {TouchableOpacity } from 'react-native';

export default SingleClickTouchableOpacity = (props) => {
let buttonClicked = false
return(
    <TouchableOpacity {...props}  onPress={() => {
        if(buttonClicked){
            return
        }
        props.onPress();
        buttonClicked = true 
        setTimeout(() => {
            buttonClicked = false
          }, 1000);
    }}>
        {props.children}
    </TouchableOpacity>
)
}