javascript 在 React Native 中防止双击
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/47102946/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Prevent Double tap in React native
提问by gourav.singhal
How to prevent a user from tapping a button twice in React native?
如何防止用户在 React Native 中点击按钮两次?
i.e. A user must not be able tap twice quickly on a touchable highlight
即用户不能在可触摸的突出显示上快速点击两次
回答by Patrick Wozniak
https://snack.expo.io/@patwoz/withpreventdoubleclick
https://snack.expo.io/@pattwoz/withpreventdoubleclick
Use this HOC to extend the touchable components like TouchableHighlight, Button ...
使用此 HOC 扩展可触摸组件,如 TouchableHighlight、Button ...
import debounce from 'lodash.debounce'; // 4.0.8
const withPreventDoubleClick = (WrappedComponent) => {
class PreventDoubleClick extends React.PureComponent {
debouncedOnPress = () => {
this.props.onPress && this.props.onPress();
}
onPress = debounce(this.debouncedOnPress, 300, { leading: true, trailing: false });
render() {
return <WrappedComponent {...this.props} onPress={this.onPress} />;
}
}
PreventDoubleClick.displayName = `withPreventDoubleClick(${WrappedComponent.displayName ||WrappedComponent.name})`
return PreventDoubleClick;
}
Usage
用法
import { Button } from 'react-native';
import withPreventDoubleClick from './withPreventDoubleClick';
const ButtonEx = withPreventDoubleClick(Button);
<ButtonEx onPress={this.onButtonClick} title="Click here" />
回答by Oleksandr Cherniavenko
Use property Button.disabled
使用属性Button.disabled
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, View, Button } from 'react-native';
export default class App extends Component {
state={
disabled:false,
}
pressButton() {
this.setState({
disabled: true,
});
// enable after 5 second
setTimeout(()=>{
this.setState({
disabled: false,
});
}, 5000)
}
render() {
return (
<Button
onPress={() => this.pressButton()}
title="Learn More"
color="#841584"
disabled={this.state.disabled}
accessibilityLabel="Learn more about this purple button"
/>
);
}
}
// skip this line if using Create React Native App
AppRegistry.registerComponent('AwesomeProject', () => App);
回答by Prateek Surana
If you are using react navigation then use this format to navigate to another page.
this.props.navigation.navigate({key:"any",routeName:"YourRoute",params:{param1:value,param2:value}})
如果您使用的是 React 导航,则使用此格式导航到另一个页面。
this.props.navigation.navigate({key:"any",routeName:"YourRoute",params:{param1:value,param2:value}})
The StackNavigator would prevent routes having same keys to be pushed in the stack again.
You could write anything unique as the keyand the paramsprop is optional if you want to pass parameters to another screen.
StackNavigator 将阻止具有相同键的路由再次推送到堆栈中。如果您想将参数传递到另一个屏幕,您可以编写任何独特的东西,因为 thekey和paramsprop 是可选的。
回答by Metalliza
I use it by refer the answer above. 'disabled' doesn't have to be a state.
我通过参考上面的答案来使用它。“禁用”不一定是一个状态。
import React, { Component } from 'react';
import { TouchableHighlight } from 'react-native';
class PreventDoubleTap extends Component {
disabled = false;
onPress = (...args) => {
if(this.disabled) return;
this.disabled = true;
setTimeout(()=>{
this.disabled = false;
}, 500);
this.props.onPress && this.props.onPress(...args);
}
}
export class ButtonHighLight extends PreventDoubleTap {
render() {
return (
<TouchableHighlight
{...this.props}
onPress={this.onPress}
underlayColor="#f7f7f7"
/>
);
}
}
It can be other touchable component like TouchableOpacity.
它可以是其他可触摸组件,如 TouchableOpacity。
回答by Rajesh Nasit
Agree with Accepted answer but very simple way , we can use following way
同意接受的答案但非常简单的方法,我们可以使用以下方法
import debounce from 'lodash/debounce';
componentDidMount() {
this.onPressMethod= debounce(this.onPressMethod.bind(this), 500);
}
onPressMethod=()=> {
//what you actually want on button press
}
render() {
return (
<Button
onPress={() => this.onPressMethod()}
title="Your Button Name"
/>
);
}
回答by Littletime
The accepted solution works great, but it makes it mandatory to wrap your whole component to achieve the desired behavior. I wrote a custom React hook that makes it possible to only wrap your callback:
公认的解决方案效果很好,但它必须包装整个组件以实现所需的行为。我写了一个自定义的 React 钩子,它可以只包装你的回调:
useTimeBlockedCallback.js
useTimeBlockedCallback.js
import {?useRef } from 'react'
export default (callback, timeBlocked = 2000) => {
const isBlockedRef = useRef(false)
const unblockTimeout = useRef(false)
return (...callbackArgs) => {
if (!isBlockedRef.current) {
callback(...callbackArgs)
}
clearTimeout(unblockTimeout.current)
unblockTimeout.current = setTimeout(() => isBlockedRef.current = false, timeBlocked)
isBlockedRef.current = true
}
}
Usage:
用法:
yourComponent.js
你的组件.js
import React from 'react'
import {?View, Text } from 'react-native'
import useTimeBlockedCallback from '../hooks/useTimeBlockedCallback'
export default () => {
const callbackWithNoArgs = useTimeBlockedCallback(() => {
console.log('Do stuff here, like opening a new scene for instance.')
})
const callbackWithArgs = useTimeBlockedCallback((text) => {
console.log(text + ' will be logged once every 1000ms tops')
})
return (
<View>
<Text onPress={callbackWithNoArgs}>Touch me without double tap</Text>
<Text onPress={() => callbackWithArgs('Hello world')}>Log hello world</Text>
</View>
)
}
The callback is blocked for 1000ms after being called by default, but you can change that with the hook's second parameter.
默认情况下,回调在被调用后会被阻止 1000 毫秒,但您可以使用钩子的第二个参数更改它。
回答by André Alencar
I have a very simple solution using runAfterInteractions:
我有一个使用 runAfterInteractions 的非常简单的解决方案:
_GoCategoria(_categoria,_tipo){
if (loading === false){
loading = true;
this.props.navigation.navigate("Categoria", {categoria: _categoria, tipo: _tipo});
}
InteractionManager.runAfterInteractions(() => {
loading = false;
});
};
回答by Peretz30
My implementation of wrapper component.
我的包装器组件的实现。
import React, { useState, useEffect } from 'react';
import { TouchableHighlight } from 'react-native';
export default ButtonOneTap = ({ onPress, disabled, children, ...props }) => {
const [isDisabled, toggleDisable] = useState(disabled);
const [timerId, setTimerId] = useState(null);
useEffect(() => {
toggleDisable(disabled);
},[disabled]);
useEffect(() => {
return () => {
toggleDisable(disabled);
clearTimeout(timerId);
}
})
const handleOnPress = () => {
toggleDisable(true);
onPress();
setTimerId(setTimeout(() => {
toggleDisable(false)
}, 1000))
}
return (
<TouchableHighlight onPress={handleOnPress} {...props} disabled={isDisabled} >
{children}
</TouchableHighlight>
)
}
回答by zino
You can also show a loading gif whilst you await some async operation. Just make sure to tag your onPresswith async () => {}so it can be await'd.
您还可以在等待一些异步操作时显示加载 gif。只要确保标记你onPress,async () => {}这样它就可以被await'd。
import React from 'react';
import {View, Button, ActivityIndicator} from 'react-native';
class Btn extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: false
}
}
async setIsLoading(isLoading) {
const p = new Promise((resolve) => {
this.setState({isLoading}, resolve);
});
return p;
}
render() {
const {onPress, ...p} = this.props;
if (this.state.isLoading) {
return <View style={{marginTop: 2, marginBottom: 2}}>
<ActivityIndicator
size="large"
/>
</View>;
}
return <Button
{...p}
onPress={async () => {
await this.setIsLoading(true);
await onPress();
await this.setIsLoading(false);
}}
/>
}
}
export default Btn;

