Expo Barcode Scanner stop working after navigate screen - javascript

So, I'm facing a problem when I navigate to my scanner screen and go back the previous screen, then navigate again to my scanner screen, barcode scanner does not working. even console logs does not working. I have to clear cashe and all data from expo app in order to work scanner screen again. I really don't know what causing the porblem but highly suspicious about Navigation. Can anyone help me pls?
Im adding my Scanner Screen right below.
import React, { useState, useEffect } from "react";
import {
Text,
View,
FlatList,
Button,
Modal,
Pressable,
Alert,
StyleSheet,
} from "react-native";
import { BarCodeScanner } from "expo-barcode-scanner";
import axios from "axios";
import { localIP, ngrokServer } from "../constants";
import allStyles from "../components/molecules/Styles";
const styles = allStyles;
export default function ScannerScreen({ navigation }) {
const [hasPermission, setHasPermission] = useState(null);
const [scanned, setScanned] = useState(false);
useEffect(() => {
setReset(false);
});
useEffect(() => {
(async () => {
const { status } = await BarCodeScanner.requestPermissionsAsync();
setHasPermission(status === "granted");
})();
}, []);
const handleBarCodeScanned = async ({ type, data }) => {
setScanned(true);
console.log("Data: ", data);
};
if (hasPermission === null) {
return <Text>Requesting for camera permission</Text>;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<View style={styles.scannerScreenContainer}>
<BarCodeScanner
onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
style={StyleSheet.absoluteFillObject}
/>
{scanned && reset && (
<Button title={"Tap to Scan Again"} onPress={() => setScanned(false)} />
)}
</View>
);
}
I'm using axios.post and thought maybe that was the cause of problem but when I removed that code block and run again it doesn't scan the QR code.

I had the same issue and I fixed it by adding a listener for focus events (emitted when the screen comes into focus).
This is what it looks like:
useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
// do something - for example: reset states, ask for camera permission
setScanned(false);
setHasPermission(false);
(async () => {
const { status } = await BarCodeScanner.requestPermissionsAsync();
setHasPermission(status === "granted");
})();
});
// Return the function to unsubscribe from the event so it gets removed on unmount
return unsubscribe;
}, [navigation]);
Try using this code and see if it works.
Source: https://reactnavigation.org/docs/navigation-events/#navigationaddlistener

Related

How to I get rid of Console Warning: expo-app-loading is deprecated in favour of expo-splash-screen?

I keep getting this error that says:
expo-app-loading is deprecated in favour of expo-splash-screen
Here's the code for my Splash Screen in App.js
export default function App() {
const [IsReady, SetIsReady] = useState(false);
const LoadFonts = async () => {
await useFonts();
};
if (!IsReady) {
return (
<AppLoading
startAsync={LoadFonts}
onFinish={() => SetIsReady(true)}
onError={() => {}}
/>
);
}
SplashScreen.hideAsync();
setTimeout(SplashScreen.hideAsync, 2000);
return (
<NavigationContainer style={styles.container}>
<UserStack/>
</NavigationContainer>
);
}
As per the expo documentation, you should try something like this, using expo-splash-screen
import React, { useCallback, useEffect, useState } from 'react';
import { Text, View } from 'react-native';
import Entypo from '#expo/vector-icons/Entypo';
import * as SplashScreen from 'expo-splash-screen';
import * as Font from 'expo-font';
export default function App() {
const [appIsReady, setAppIsReady] = useState(false);
useEffect(() => {
async function prepare() {
try {
// Keep the splash screen visible while we fetch resources
await SplashScreen.preventAutoHideAsync();
// Pre-load fonts, make any API calls you need to do here
await Font.loadAsync(Entypo.font);
// Artificially delay for two seconds to simulate a slow loading
// experience. Please remove this if you copy and paste the code!
await new Promise(resolve => setTimeout(resolve, 2000));
} catch (e) {
console.warn(e);
} finally {
// Tell the application to render
setAppIsReady(true);
}
}
prepare();
}, []);
const onLayoutRootView = useCallback(async () => {
if (appIsReady) {
// This tells the splash screen to hide immediately! If we call this after
// `setAppIsReady`, then we may see a blank screen while the app is
// loading its initial state and rendering its first pixels. So instead,
// we hide the splash screen once we know the root view has already
// performed layout.
await SplashScreen.hideAsync();
}
}, [appIsReady]);
if (!appIsReady) {
return null;
}
return (
<View
style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}
onLayout={onLayoutRootView}>
<Text>SplashScreen Demo! 👋</Text>
<Entypo name="rocket" size={30} />
</View>
);
}
First install with expo install expo-splash-screen
You can also configure your app with a SplashScreen from the start with
npx create-react-native-app -t with-splash-screen.
You are using a package that has been deprecated by expo and you have to switch to a more recent package.
Delete any code that is related to expo-app-loading package check this , and use expo-splash-screen instead check this
Note that if you are using a google font via '#expo-google-fonts', your code should look like that :
import * as SplashScreen from 'expo-splash-screen';
import React, { useCallback, useContext, useState, useEffect } from "react";
import { useFonts, Karla_300Light, Karla_400Regular, Karla_600SemiBold, Karla_800ExtraBold } from '#expo-google-fonts/karla';
SplashScreen.preventAutoHideAsync(); // Keep the splash screen visible while we fetch resources
function App() {
const [fontsLoaded] = useFonts({
Karla_300Light,
Karla_400Regular,
Karla_600SemiBold,
Karla_800ExtraBold,
Caveat_700Bold,
})
useEffect(() => {
async function prepare() {
await SplashScreen.preventAutoHideAsync();
}
prepare();
}, []);
const onLayoutRootView = useCallback(async () => {
if (fontsLoaded) {
await SplashScreen.hideAsync();
}
}, [fontsLoaded]);
if (!fontsLoaded) {
return null;
}
return (
<AuthProvider>
<NavigationContainer
theme={navigationTheme}
onReady={onLayoutRootView}
>
{user ? <AppNavigator /> : <AuthNavigator />}
</NavigationContainer>
</AuthProvider>
);
}
export default App

React Native Firebase update works but hangs app and closes modal

I am attempting to enable a Thumbs Up option where when pressed it retrieves the current number of thumbs up in my database for an item, increments it, then updates it. As you can see I've put 2 "here" console.logs, both log to the screen. I get no errors or catches, and the database updates (immediately when pressed). So it technically works, but then there is a lag/hang, for probably 7 seconds where the thumb icon shows as pressed the whole time like it's stuck, and then the modal goes away back to the main screen. As if it "crashed". If I take the update out, there is no hang and the modal remains open until I choose to close it. So it has to be that code. Do you see any glaring errors in my logic?
Update: I've traced the issue possibly to the screen that renders this component. I populate a flatlist using the firebase onValue, of which each object has this "thumbs up" feature. When I take out the onValue section and replace it with a single dummy data object instead, the thumbs up works perfectly. So there must be a problem with the listener maybe not unsubscribing right the way I have it. Previous screen code added.
import React, {useState} from "react";
import { Image, StyleSheet, TouchableOpacity, View } from "react-native";
import AppText from "../components/AppText";
import * as Sentry from 'sentry-expo';
import { ref, child, get, query, onValue, update } from "firebase/database";
function HotDidItWork({indexStore, db, auth}) {
var user = auth.currentUser;
if (!user){
return (
<></>
)
}
const [upPressed, setUpPressed] = useState(false);
const [displayText, setDisplayText] = useState('');
async function didPressUp(){
setUpPressed(true);
const dbRef = ref(db, 'deals/' + indexStore);
if (displayText == ''){
get(query(dbRef))
.then((usersSnapshot)=> {
if (usersSnapshot.exists()) {
let thumbsUpCount = usersSnapshot.val().thumbsUp;
thumbsUpCount = parseInt(thumbsUpCount);
thumbsUpCount += 1;
console.log('here 1');
update(dbRef, {thumbsUp: thumbsUpCount.toString()})
.then(()=> {
console.log('here 2');
setDisplayText('Thanks!');
})
.catch((e)=> {
console.log('error 1: ' + e.message);
})
} else {
console.log("No data available");
}
})
.catch((e)=> {
console.log("error 2: " + e.message);
})
}
}
return (
<View>
<View style={styles.messageContainer}>
<AppText style={upPressed == false && downPressed == false ? styles.didItWork : styles.pressed}>Did this deal work for you?</AppText>
<AppText style={downPressed == true || upPressed == true ? styles.didItWork : styles.pressed}>{displayText}</AppText>
</View>
<View style={styles.thumbs}>
<TouchableOpacity onPress={() => didPressUp()}>
<Image
style={styles.thumbsUp}
source={require("../assets/thumbsUp.png")}
/>
</TouchableOpacity>
</View>
</View>
);
}
export default HotDidItWork;
Previous Screen that renders flatlist of obj with thumbs up feature (I now believe this is where the error is):
import React, { useState, useEffect } from "react";
import {
FlatList,
Image,
ImageBackground,
Platform,
SafeAreaView,
StyleSheet,
TextInput,
TouchableOpacity,
View,
} from "react-native";
import HotCardFav from "../components/HotCardFav";
import { ref, child, get, query, onValue, update } from "firebase/database";
import ListItemSeparator from "../components/ListItemSeparator";
import CardItemDeleteAction from "../components/CardItemDeleteAction";
import { MaterialCommunityIcons } from "#expo/vector-icons";
import { ActivityIndicator } from "react-native";
import {db, auth} from '../../src/config.js';
import AppText from "../components/AppText";
import colors from "../config/colors";
import * as Sentry from 'sentry-expo';
import Header from '../components/Header';
import { ThemeProvider, useFocusEffect } from '#react-navigation/native';
let initialMessagesFav = [];
let listViewRef;
function FavoritesHotScreen() {
var user = auth.currentUser;
if (user == null) {
return (
<></>
)
}
const [loading, setLoading] = useState(false);
const [messagesFav, setMessagesFav] = useState(initialMessagesFav);
const [messagesFavHold, setMessagesFavHold] = useState(initialMessagesFav);
const [refreshing, setRefreshing] = useState(false);
useFocusEffect(
React.useCallback( () => {
async function fetchData() {
// You can await here
const response = await loadListings();
// ...
return () => response();
}
fetchData();
}, [])
);
async function lookupUser(){
const dbRef = ref(db, 'users/' + user.uid);
const usersSnapshot = await get(query(dbRef));
return usersSnapshot;
}
const loadListings = async () => {
let favs = [];
let favsArray = [];
updateInput('');
setLoading(true);
console.log('exists 2');
lookupUser()
.then((snapshot) => {
if (snapshot.exists()) {
favs = snapshot.child("favorites").val();
if (favs != null){
favsArray = favs.split(',');
}
const dbRef = ref(db, 'deals');
return onValue(dbRef , (snapshot) => {
let testData = [];
let searchData = [];
snapshot.forEach((childSnapshot)=>{
let found = favsArray.find(function (element) {
return element == childSnapshot.val().indexStore;
});
if (found != undefined){
testData.push({
id: childSnapshot.key,
title: childSnapshot.val().title,
postedDate: childSnapshot.val().postedDate,
desc: childSnapshot.val().desc,
indexStore: childSnapshot.val().indexStore,
})
checkMessages(testData);
setLoading(false);
}
})
})
.catch((error) => Sentry.Native.captureException('Error FavoritesScreen function loadListings 2 ' + error));
}
const renderItem = ({ item }) => (<HotCardFav
title={item.title}
desc={item.desc}
indexStore={item.id}
postedDate={item.postedDate}
/>);
function checkMessages(testData){
const filtered = testData.filter(country => {
return (country.title != 'NA')
})
setMessagesFav(filtered);
setMessagesFavHold(testData);
setLoading(false);
}
let messagesShow = messagesFav.sort((a, b) => {
const messageA = new Date(parseInt(a.postedDate));
const messageB = new Date(parseInt(b.postedDate));
let comparison = 0;
if (messageA > messageB) {
comparison = 1;
} else if (messageA < messageB) {
comparison = -1;
}
return comparison * -1;
});
return (
<SafeAreaView style={styles.wholeThing}>
<Header image={require('../assets/longlogo4.png')} />
<View style={loading ? styles.activity : styles.none}>
<ActivityIndicator animating={loading} size="large" color="#0000ff" />
</View>
<FlatList
data={messagesShow}
keyExtractor={(messagesShow) => messagesShow.id.toString()}
renderItem={renderItem}
ItemSeparatorComponent={ListItemSeparator}
contentContainerStyle={styles.messagesList}
refreshing={refreshing}
ref={(ref) => {
listViewRef = ref;
}}
/>
</SafeAreaView>
);
}
export default FavoritesHotScreen;
Ok I figured it out here's what I found in case it helps someone in the future. The problem was in my main screen loadlistings() function (that I posted as an edit). It uses onValue to retrieve firebase data which attaches a listener which means ANYTIME data on my database changes, it rerenders the flatlist, entirely. Which automatically closes my modal since it's defaulted to be closed when the screen starts. So by me pressing the "thumbs up", it was changing data, the listener responded, rerendered the flatlist with a closed modal. Maybe this should have been obvious but it wasn't for me. I fixed it by adding a simple "onlyOnce" flag to the end of the onValue per firebase documentation:
return onValue(dbRef , (snapshot) => {
let testData = [];
let searchData = [];
snapshot.forEach((childSnapshot)=>{
let found = favsArray.find(function (element) {
return element == childSnapshot.val().indexStore;
});
if (found != undefined){
testData.push({
id: childSnapshot.key,
title: childSnapshot.val().title,
postedDate: childSnapshot.val().postedDate,
desc: childSnapshot.val().desc,
indexStore: childSnapshot.val().indexStore,
})
checkMessages(testData);
setLoading(false);
})
},{
onlyOnce: true
})

React native launches first launch screen repeatedly

I have created app in react native with a screen that will appear only on first app entry.
Other times it just load it AsyncStorage value to check if the app has been launched before.
The screen does appear, but on every app launch. I want it to appear only on first launch.
As far as I know the following code should work, but something collapsing here with the async probably..
export default function App() {
const [selected, setSelected] = useState(false);
const verifyHasLaunched = async () => {
try {
const hasLaunched = await AsyncStorage.getItem(HAS_LAUNCHED);
if(hasLaunched){
setSelected(true);
}
setSelected(false);
} catch (err) {
setSelected(false);
}
};
useEffect(() => verifyHasLaunched, []);
//The rest of the code - irrelevant
//By using Selected state I show different screen and not first launch screen.
CheckIfFirstLaunch function
//Save the language as AsyncStorage for other times the user will open the app
async function setAppLaunched(en) {
AsyncStorage.setItem(HAS_LAUNCHED, "true");
AsyncStorage.setItem(en ? ENGLISH : HEBREW, "true");
if(await AsyncStorage.getItem(HEBREW)){
i18n.locale = "he";
I18nManager.forceRTL(true);
}
else{
i18n.locale = "en";
I18nManager.forceRTL(false);
}
}
//If first launch show this screen
function CheckIfFirstLaunch({ onSelect }) {
const navigation = useNavigation();
const selectLaunched = (value) => {
if(value){
i18n.locale = "en";
I18nManager.forceRTL(false);
}
else{
i18n.locale = "he";
I18nManager.forceRTL(true);
}
setAppLaunched(value);
onSelect();
navigation.navigate('Login');
};
return (
<View>
<Text>Choose Language</Text>
<Button onPress={() => selectLaunched(false)} title="Hebrew"/>
<Button onPress={() => selectLaunched(true)} title="English"/>
</View>
);
}
Expected behavior
CheckIfFirstLaunch() should appear only once on first launch.
Current behavior
CheckIfFirstLaunch() appears on every launch.
How can I create React Native first launch screen correctly?
if(hasLaunched){
setSelected(true);
} else {
setSelected(false);
}

Custom hook function not being called in React

I am trying to call my fetchPlants function, but I cannot see to figure out why it is NOT being called.
/screens/RecipeScreen.js
import usePlants from '../hooks/usePlants';
// Call our custom hook
const [fetchPlants, plantResults] = usePlants();
// ...other code...
<RecipeSearch
recipeSearch={recipeSearch}
onRecipeSearchChange={setRecipeSearch}
onRecipeSearchSubmit={() => fetchPlants(recipeSearch)}
/>
/components/RecipeSearch.js
const RecipeSearch = ({
onRecipeSearchChange,
onRecipeSearchSubmit,
recipeSearch,
}) => {
return (
console.log(recipeSearch); // This prints out nicely...
<View>
<View>
<TextInput
placeholder='Find a plant...'
value={recipeSearch}
onChangeText={onRecipeSearchChange}
onEndEditing={onRecipeSearchSubmit}
/>
</View>
</View>
);
};
/hooks/usePlants.js
import { useState, useEffect } from 'react';
import plantsApi from '../api/plants';
export default () => {
const [plantResults, setPlantResults] = useState([]);
const fetchPlants = async searchTerm => {
console.log('searchTerm... HERE IS THE QUERY', searchTerm); // this never gets hit
try {
const response = await plantsApi.get('').then(response => {
console.log(response);
setPlantResults(response);
});
} catch (err) {
console.log(err);
}
};
return [fetchPlants, plantResults];
};
I initially thought that maybe I was calling fetchPlants() too early (before recipeSearch had any state), but I don't think so, because it is still able to console.log(searchRecipe) properly.
Update it was working ALL along. When I was testing it with the iOS simulator I needed to hit the "ENTER" key on my computer because I am using the React Native onEndEditing prop.

Prevent Double tap in React native

How to prevent a user from tapping a button twice in React native?
i.e. A user must not be able tap twice quickly on a touchable highlight
https://snack.expo.io/#patwoz/withpreventdoubleclick
Use this HOC to extend the touchable components like 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" />
Use property 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);
Here is my simple hook.
import { useRef } from 'react';
const BOUNCE_RATE = 2000;
export const useDebounce = () => {
const busy = useRef(false);
const debounce = async (callback: Function) => {
setTimeout(() => {
busy.current = false;
}, BOUNCE_RATE);
if (!busy.current) {
busy.current = true;
callback();
}
};
return { debounce };
};
This can be used anywhere you like. Even if it's not for buttons.
const { debounce } = useDebounce();
<Button onPress={() => debounce(onPressReload)}>
Tap Me again and adain!
</Button>
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"
/>
);
}
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.
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}})
The StackNavigator would prevent routes having same keys to be pushed in the stack again.
You could write anything unique as the key and the params prop is optional if you want to pass parameters to another screen.
The accepted solution works great, but it makes it mandatory to wrap your whole component and to import lodash to achieve the desired behavior.
I wrote a custom React hook that makes it possible to only wrap your callback:
useTimeBlockedCallback.js
import { useRef } from 'react'
export default (callback, timeBlocked = 1000) => {
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
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.
I have a very simple solution using runAfterInteractions:
_GoCategoria(_categoria,_tipo){
if (loading === false){
loading = true;
this.props.navigation.navigate("Categoria", {categoria: _categoria, tipo: _tipo});
}
InteractionManager.runAfterInteractions(() => {
loading = false;
});
};
Did not use disable feature, setTimeout, or installed extra stuff.
This way code is executed without delays. I did not avoid double taps but I assured code to run just once.
I used the returned object from TouchableOpacity described in the docs https://reactnative.dev/docs/pressevent and a state variable to manage timestamps. lastTime is a state variable initialized at 0.
const [lastTime, setLastTime] = useState(0);
...
<TouchableOpacity onPress={async (obj) =>{
try{
console.log('Last time: ', obj.nativeEvent.timestamp);
if ((obj.nativeEvent.timestamp-lastTime)>1500){
console.log('First time: ',obj.nativeEvent.timestamp);
setLastTime(obj.nativeEvent.timestamp);
//your code
SplashScreen.show();
await dispatch(getDetails(item.device));
await dispatch(getTravels(item.device));
navigation.navigate("Tab");
//end of code
}
else{
return;
}
}catch(e){
console.log(e);
}
}}>
I am using an async function to handle dispatches that are actually fetching data, in the end I'm basically navigating to other screen.
Im printing out first and last time between touches. I choose there to exist at least 1500 ms of difference between them, and avoid any parasite double tap.
You can also show a loading gif whilst you await some async operation. Just make sure to tag your onPress with async () => {} so it can be 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;
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>
)
}

Categories

Resources