render function not rendering anything React Native - javascript

Nothing is rendering on screen. No clue why its happening, No error anywhere. Wondering why nothing is showing on screen. Getting data from API properly. Code is given below:
import React, { Component } from 'react';
import { StyleSheet, ScrollView, TouchableOpacity, Text, View } from 'react-native';
import { Container, Content, Grid, Row, Col } from 'native-base';
import axios from 'axios';
import ItemCard from '../components/ItemCard';
export default class ItemHorizontalScreen extends Component {
constructor(props) {
super(props)
this.state = {
items: []
}
}
componentWillMount() {
axios.get('http://rallycoding.herokuapp.com/api/music_albums').then(response =>
this.setState({
items: response.data
}))
.catch((error) => {
console.error(error);
})
}
renderHorizontalContents() {
const rowItems = this.state.items
rowItems.map((rowItem, index) => {
return (
<TouchableOpacity key={index}>
<Text>{rowItem.title}</Text>
</TouchableOpacity>
)
})
}
render() {
return (
<View>
{this.renderHorizontalContents()}
</View>
)
}
}

Your renderHorizontalContents() should return the list:
renderHorizontalContents() {
const rowItems = this.state.items
return rowItems.map((rowItem, index) => {
return (
<TouchableOpacity key={index}>
<Text>{rowItem.title}</Text>
</TouchableOpacity>
)
})
}
Also, semi-related, as of React 16.3 React team advises not to use componentWillMount(). You should fetch the data in componentDidMount() LifeCycle hook.
More on componentWillMount() deprecation:
https://github.com/styled-components/styled-components/issues/1575

Try this. The issue is renderHorizontalContents() is not returning so you have to return elements which map returns for you
Also regarding adding key, if items array contains unique id per object then use that is as key that is recommended. Index is always second option if you don’t have unique id from data. Also when adding index as key you should add something like I did below instead of adding index as key directly.
renderHorizontalContents() {
const { items } = this.state;
return items.map((rowItem, index) => {
return (
<TouchableOpacity key={"Key"+index}>
<Text>{rowItem.title}</Text>
</TouchableOpacity>
)
})
}

Related

Unable to re-render FlatList using extraData prop and State Variable

What I am trying to do
I am trying to get a set of songs play one after another. My app leverages Expo-Av API for playing the songs.
The app is consisted of two components. App.js and a ChildComponent.
App.js renders three songs using a flatlist. It also keeps track of which song has played using a state variable. The sequence of events as I intend them to happen are as follows:
Expected Steps
nextSongToPlay index is set to 0 when the app loads
Flatlist renders 3 ChildComponents using the Data array
Each ChildComponent is passed the index of renderItem as well as the nextSongToPlay
Within the first instance of ChildComponent, once the audio has been loaded using the loadAsync() function which returns a promise. If the promise is resolved AND the index (zero 0) and nextSongToPlay (zero 0 at first run) props are equal, the button within the ChildComponent is pressed by calling its reference (ref.current.props.onPress() )
Once the song finished playing the function passed to onPlayBackStatusUpdate method in ChildComponent is run (looking at the playBackObjectStatus.didJustFinish) and if the didJustFinish property is true, the NextSongToPlay method in App.js is called which has been passed to ChildComponent as a prop.
Once the NextSongToPlay method is run, the netSongToPlay state variable in App.js is incremented by 1.
This causes the re-render of App.js along with the FlatList. In
order to force the FlatList to re-render (since FlatList is a pure
component), the nextSongToPlay variable is passed to the extraData
prop within FlatList
The renderItem is ran again and this time the second ChildComponent will receive index (1) and nextSongToPlay (1). This will cause the loadAsync() method in second ChildComponent to call the ref.current.props.onPress() and play the song.
The process should continue until the last song in the Data array.
Here is what my App.js looks like:
import { View, Text, FlatList } from "react-native";
import React, { useState, useRef, useEffect } from "react";
import ChildComponent from "./ChildComponent";
const Data = [
{
key: "1",
song: "https://www2.cs.uic.edu/~i101/SoundFiles/CantinaBand3.wav",
},
{
key: "2",
song: "https://www2.cs.uic.edu/~i101/SoundFiles/CantinaBand3.wav",
},
{
key: "3",
song: "https://www2.cs.uic.edu/~i101/SoundFiles/CantinaBand3.wav",
},
];
export default function App() {
const [nextSongToPlay, setNextSongToPlay] = useState(0);
const shouldPlayOnItsOwn = useRef(false);
useEffect(() => {
return () => (shouldPlayOnItsOwn.current = false);
});
const NextSongToPlay = () => {
setNextSongToPlay(nextSongToPlay + 1);
};
const setShouldPlayOnItsOwn = () => {
shouldPlayOnItsOwn.current = true;
};
const renderItem = ({ item, index }) => {
return (
<View style={{ marginTop: 10 }}>
<ChildComponent
path={item.path}
NextSongToPlay={() => NextSongToPlay()}
nextSongToPlay={nextSongToPlay}
index={index}
songURL={item.song}
setShouldPlayOnItsOwn={setShouldPlayOnItsOwn}
shouldPlayOnItsOwn={shouldPlayOnItsOwn.current}
/>
</View>
);
};
return (
<View
style={{ justifyContent: "center", alignItems: "center", marginTop: 200 }}
>
<FlatList
data={Data}
renderItem={renderItem}
extraData={nextSongToPlay}
/>
<Text style={{ marginTop: 30 }}>
{" "}
Number of Songs Played: {nextSongToPlay}{" "}
</Text>
</View>
);
}
And this is what my ChildComponent looks like:
import { View, Button } from "react-native";
import React, { useRef, useEffect } from "react";
import { Audio } from "expo-av";
export default function ChildComponent(props) {
const sound = useRef(new Audio.Sound());
const PlayBackStatus = useRef();
const ref = useRef();
const alreadyPlayed = useRef(false);
useEffect(() => {
LoadAudio();
return () => sound.current.unloadAsync();
}, []);
const LoadAudio = async () => {
PlayBackStatus.current = sound.current
.loadAsync({ uri: props.songURL })
.then((res) => {
console.log(`load result : ${res}`);
if (props.index === props.nextSongToPlay && props.shouldPlayOnItsOwn) {
ref.current.props.onPress();
}
})
.catch((err) => console.log(err));
};
const PlayAuido = async () => {
alreadyPlayed
? sound.current.replayAsync()
: (PlayBackStatus.current = sound.current
.playAsync()
.then(() =>
console.log(`result of playing: ${PlayBackStatus.current}`)
)
.catch((err) => console.log(`PlayAsync Failed ${err}`)));
};
sound.current.setOnPlaybackStatusUpdate((playBackObjectStatus) => {
console.log(
`Audio Finished Playing: ${playBackObjectStatus.didJustFinish}`
);
if (playBackObjectStatus.didJustFinish) {
console.log(
`Inside the If Condition, Did the Audio Finished Playing?: ${playBackObjectStatus.didJustFinish}`
);
alreadyPlayed.current = true;
props.NextSongToPlay();
}
});
const onPressHandler = () => {
PlayAuido();
props.setShouldPlayOnItsOwn();
};
return (
<View>
<Button title="Play Sound" onPress={onPressHandler} ref={ref} />
</View>
);
}
What is the Problem
Everything seems to work fine until step 7 in the expected steps section above. Even though the nextSongToPlay state variable does increment after the first song is played, the Flatlist doesnot seem to be getting rendered.
Here is the snack to reproduce this.
Any help in determining the issue is greatly appreciated!
Thanks in advance!

Problem with useState, UseEffect when saving data when getting data

I am new to react native and I want on the welcome screen of my application to click on a request to an api using axios and the data is saved in a variable using useState and then use this data in another class (AllProductCategory .js) without having to make the request back to the api.
I am using React native 0.62 hooks react navigation 5 and axios.
I have the following in the Navigation.js file. A context that has a useMemo as its value, which contains a return so that it returns an array with information that it brings from an application using axios. the class looks like this:
In this class skip certain lines of code that have nothing to do with the problem I am currently having.
export default function Navigation() {
const [allproducts, setAllproducts] = useState([]);
useEffect(() => {
const _loadAllCategories = async () => {
await axiosClient
.get("/service/product_available")
.then(function (response) {
console.log("Data antes de pasarlo al useState ", response.data);
setAllproducts(response.data);
console.log("Los productos son: ", allproducts);
})
.catch(function (error) {
console.log("Error obteniendo el token", error);
});
};
_loadAllCategories();
}, []);
const authContext = useMemo(
() => ({
getAllProducts: () => {
return allproducts;
},
}),
[]
);
return (
<AuthContext.Provider value={authContext}>
{state.isLoading ? (
<SplashStackScreen />
) : state.userToken == null ? (
<PrincipalStackScreen />
) : (
<MyDrawer />
)}
</AuthContext.Provider>
);
}
With this file what I want is for the data that brings all the products to be loaded when the splash screen is loading and so when I want to use this data on another screen, just call the context variable and return the data without having to make another request to the api.
Then in the class I implement the call of this data using the context
const { getAllProducts } = React.useContext(AuthContext);
const allProducts = getAllProducts();
The complete class is like this:
import React, { useState, useEffect } from "react";
import { View, Text, FlatList, StyleSheet, TouchableOpacity, Dimensions, Image } from "react-native";
import { AuthContext } from "../../context";
var { height, width } = Dimensions.get("window");
export default function AllProductCategoryScreen() {
const { getAllProducts } = React.useContext(AuthContext);
const allProducts = getAllProducts();
function Product_Category({ name, image }) {
console.log("name e image", name);
return (
<View>
<TouchableOpacity>
<Image style={styles.imageCategory} source={{ uri: image }} />
<Text>{name}</Text>
</TouchableOpacity>
</View>
);
}
return (
<View>
<Text>Todas las categorias</Text>
<View style={{ alignItems: "center" }}>
<FlatList
scrollEnabled={true}
numColumns={2}
data={allProducts}
renderItem={({ item }) => (
<Product_Category name={item.name} image={item.imagePath} />
)}
keyExtractor={(item, index) => index.toString()}
/>
</View>
</View>
);
}
My app.js is as follows:
import React from 'react';
import Navigation from "./src/components/Navigation/Navigation"
export default function App() {
return <Navigation />
}
The problem that I currently have is that when I start my app, I show that the request is made with axios and it brings the data correctly, however the useState is not filled with the data that the axios responds to me (it prints []). However if I save changes being in the navigation.js class in visual code the variable allproducts of the navigation class is filled with the data correctly and therefore in the other class where I want to display the data, it paints the data correctly.
I need that when my app loads, the data that the api brings is saved and that when using it in the other class, these data remain so that they can be used and illustrate this data on the screen.
When the function passed to useMemo is created, it captures the first value of allproducts and will always have that value. It will always return [].
In order for useMemo to run again and capture a new value, add that value to the second argument, the array. React will call the memo function whenever a value in that array changes, and then getAllProducts will be created again and capture a new value of allproducts.
const authContext = useMemo(
() => ({
getAllProducts: () => {
return allproducts;
},
}),
[allproducts]
);

React Native Hooks: unable to display values in return() from useEffect function

Using react hooks with firebase real time database with a project Im working on for the first time, the data is being retrieved and logs in the console. BUT I am unable go move out side the useEffect function to display values on the screen! Would really appreciate some help!
videoArray needs to be put in a FlatList, as you can see in the code bellow videoArray logs values in the console in useEffect function. However, once I move out that function to add it into a FlatList it is null because the values are in a local function.
My question is, how am I able to pass value of videoArray (in useEffect) into the FlatList?
import React, { useState, useEffect } from 'react'
import { FlatList, View, TouchableOpacity, Text, StyleSheet, SafeAreaView } from 'react-native';
import { Center } from '../components/Center'
import { Video } from 'expo-av';
import firebase from '../firebase'
const videoRef = firebase.database().ref('videoCollaction');
export const FeedScreen = ({ }) => {
let [videoArray, setVideo] = useState([]);
useEffect(() => {
videoRef.on('value', (childSnapshot) => {
videoArray = [];
childSnapshot.forEach((doc) => {
videoArray.push({
key: doc.key,
video: doc.toJSON().video,
});
})
})
// able to log values only here
console.log('working:', videoArray);
});
// get video uri from firebase (testing)
// readVideo = () => {
// var collection = firebase.database().ref("videoCollactionvideo" + "/video").orderByValue();
// console.log('uri', collection);
// }
return (
<SafeAreaView>
<Text>Feed Screen</Text>
{/* null here: need values to show up here*/}
{console.log(" test",videoArray)}
<FlatList
data={videoArray}
renderItem={({ item, index }) => {
return (
<View>
<Text style={{ fontSize: 35, color: 'red' }}>Video:...</Text>
<TouchableOpacity onPress={() => console.log('pressed')}><Text style={{ color: 'blue' }}>Expand</Text></TouchableOpacity>
</View>
);
}} keyExtractor={({ item }, index) => index.toString()}>
</FlatList>
</SafeAreaView>
);
}
Try this:
useEffect(() => {
const temp = []; // temp array
videoRef.on("value", childSnapshot => {
childSnapshot.forEach(doc => {
temp.push({
key: doc.key,
video: doc.toJSON().video
});
});
setVideo(temp); // update state array
});
}, []);
It seems like you are trying to update the State Hook (videoArray), but you are doing it the wrong way (it shouldn't be modified directly). Instead, use the setVideo update method which you created with the Hook (let [videoArray, setVideo] = useState([]);):
useEffect(() => {
videoRef.on('value', (childSnapshot) => {
newVideoArray = [];
childSnapshot.forEach((doc) => {
newVideoArray.push({
key: doc.key,
video: doc.toJSON().video,
});
})
})
// able to log values only here
console.log('working:', newVideoArray);
setVideo(newVideoArray);
});
Check out Using the Effect Hook for more information on how to use this specific hook (the Optimizing Performance by Skipping Effects section might be especially of interest).
In essence, this functionality is similar to your Functional Component's stateful counterparts (React.Component or React.PureComponent), where:
Constructor is the only place where you should assign this.state directly. In all other methods, you need to use this.setState() instead.
Try this:
import React, { useState, useEffect } from 'react'
import { FlatList, View, TouchableOpacity, Text, StyleSheet, SafeAreaView } from 'react-native';
import { Center } from '../components/Center'
import { Video } from 'expo-av';
import firebase from '../firebase'
const videoRef = firebase.database().ref('videoCollaction');
export const FeedScreen = ({ }) => {
let [videoArray, setVideoArray] = useState([]);
useEffect(() => {
videoRef.on('value', (childSnapshot) => {
const newVideoArray = [];
childSnapshot.forEach((doc) => {
newVideoArray.push({
key: doc.key,
video: doc.toJSON().video,
});
})
setVideoArray(newVideoArray);
})
// able to log values only here
console.log('working:', videoArray);
}, []);
console.log('State also working :) >> ', videoArray);
return (
<SafeAreaView>
<Text>Feed Screen</Text>
{/* null here: need values to show up here*/}
{console.log(" test",videoArray)}
<FlatList
data={videoArray}
renderItem={({ item, index }) => {
return (
<View>
<Text style={{ fontSize: 35, color: 'red' }}>Video:...</Text>
<TouchableOpacity onPress={() => console.log('pressed')}><Text style={{ color: 'blue' }}>Expand</Text></TouchableOpacity>
</View>
);
}} keyExtractor={({ item }, index) => index.toString()}>
</FlatList>
</SafeAreaView>
);
}

Update a list after an item triggers its own deletion

I am rendering a card in a parent component for every post that a user has. In the card, all of the data is passed down via props. I have a delete axios call that works, however I have to manually refresh the page for the page to show updates.
Any way I can have it manually update the UI?
// DASHBOARD.JS
if (this.state.posts.length > 0 && this.state.loaded === true) {
const posts = this.state.posts;
content = posts.map(post => (
<Card
key={post._id}
author={post.author}
title={post.title}
date={post.date}
body={post.body}
id={post._id}
/>
));
// CARD.JS
deleteOnClick = e => {
axios
.delete('http://localhost:5000/auth/deletePost', {
params: {
id: this.props.id
}
})
.then(res => {
console.log(res);
})
.catch(err => console.log(err));
};
I think you have two problems to fix in order to make this pattern work.
First thing first: avoid defining business logic in components used only for presentational purposes (have a read here).
So in Card component there should be no explicit definition of the deleteOnClick method, while it should receive it from above in a dedicated prop of type func.
Second thing: the list component should handle the logic of deleting items from the list through the axios call and in the then statement you should think of a way to update the list items you are using to render Cards.
Examples in pseudocode:
List Component
import React from 'react';
import Card from './Card';
export default class List extends PureComponent {
state = {
items: [],
error: null,
}
componentDidMount() {
// add axios call to retrieve items data
}
deleteItemHandler = () => {
axios
.delete('http://localhost:5000/auth/deletePost', {
params: {
id: this.props.id
}
})
.then(res => {
this.setState({
items: res.json(),
})
})
.catch(err => {
this.setState({
error: err,
})
});
};
}
render() {
const { items } = this.state;
return (
<div>
{items.map(item => (
<Card
{...item}
onClick={this.deleteItemHandler}
/>
))}
</div>
)
}
}
Card component:
import React from 'react';
import PropTypes from 'prop-types';
export default class Card extends PureComponent {
static propTypes = {
title: PropTypes.string,
// other props
onClick: PropTypes.func.isRequired,
}
// other things in this class
render() {
const { onClick, title } = this.props;
return (
<div onClick={onClick}>
<h1>{title}</h1>
</div>
)
}
}
Once you get familiar with concept of separating logic and presentation you can start introducing redux and do things at another level :)
Hope this helps!

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