react-native: PLEASE REPORT: Excessive number of pending callbacks: 501
Description
Hi,
I keep the getting the error seen on the screenshot below. For context, I’m creating an app (IOS) where users can swipe through a number of songs to listen to the audio and comment on each song.
This error warning shows when I finish swiping on a song and load the next one. Any help would be great - my app keeps crashing on my physical device (fine on simulator) after a few swipes. Full error shown below.
Version
0.66.1
Output of npx react-native info
System: OS: macOS 12.3.1 CPU: (8) arm64 Apple M1 Memory: 95.30 MB / 16.00 GB Shell: 5.8 - /bin/zsh Binaries: Node: 16.16.0 - /usr/local/bin/node Yarn: 1.22.19 - /usr/local/bin/yarn npm: 8.11.0 - /usr/local/bin/npm Watchman: 2022.06.27.00 - /opt/homebrew/bin/watchman Managers: CocoaPods: 1.11.3 - /opt/homebrew/bin/pod SDKs: iOS SDK: Platforms: DriverKit 21.4, iOS 15.5, macOS 12.3, tvOS 15.4, watchOS 8.5 Android SDK: Not Found IDEs: Android Studio: Not Found Xcode: 13.4/13F17a - /usr/bin/xcodebuild Languages: Java: Not Found npmPackages: @react-native-community/cli: Not Found react: 18.0.0 => 18.0.0 react-native: 0.69.1 => 0.69.1 react-native-macos: Not Found npmGlobalPackages: react-native: Not Found
Steps to reproduce
Swipe through songs to reproduce.
Snack, code example, screenshot, or link to a repository
StyleSheet,
Text,
View,
Dimensions,
Image,
TextInput,
FlatList,
TouchableOpacity,
ScrollView,
Keyboard,
} from 'react-native';
import React, {useState, useEffect, useRef, useMemo, useCallback} from 'react';
import {Gesture, GestureDetector} from 'react-native-gesture-handler';
import {firebase} from '@react-native-firebase/firestore';
import Colors from '../assets/utilities/Colors';
import Spotify from '../assets/img/spotify.svg';
import AsyncStorage from '@react-native-async-storage/async-storage';
import firestore from '@react-native-firebase/firestore';
import storage from '@react-native-firebase/storage';
import Ionicons from 'react-native-vector-icons/Ionicons';
import Animated, {
useAnimatedStyle,
useSharedValue,
withSpring,
runOnJS,
} from 'react-native-reanimated';
const {height: SCREEN_HEIGHT} = Dimensions.get('window');
const BottomSheet = props => {
console.log(SCREEN_HEIGHT);
const caption = props.captionProps;
const songID = props.songIDProps;
const navigation = props.navigationProps;
const [UID, setUID] = useState();
const [displayName, setDisplayName] = useState();
const [profilePicURL, setProfilePicURL] = useState();
const [inputTop, setInputTop] = useState(false);
const [commentText, setCommentText] = useState();
const [parentComments, setParentComments] = useState();
const [activeLikedComments, setActiveLikedComments] = useState([]);
const [likeChanged, setLikedChanged] = useState(false);
const [myComment, setMyComment] = useState(false);
const [bottomSheetSmall, setBottomSheetSmall] = useState(false);
const [commentID, setCommentID] = useState();
const inputRef = useRef();
const replyUsernameRef = useRef();
const [replyUsername, setReplyUsername] = useState();
const [replyActive, setReplyActive] = useState(false);
const [replyID, setReplyID] = useState();
const [parentReplies, setParentReplies] = useState();
const [viewReplies, setViewReplies] = useState(false);
const [containerUp, setContainerUp] = useState(false);
const translateY = useSharedValue(0);
const scrollTo = useCallback(
destination => {
'worklet';
translateY.value = withSpring(destination, {damping: 50});
},
[translateY],
);
const context = useSharedValue({y: 0});
const gesture = Gesture.Pan()
.onStart(() => {
context.value = {y: translateY.value};
})
.onUpdate(event => {
translateY.value = event.translationY + context.value.y;
translateY.value = Math.max(translateY.value, -269);
})
.onEnd(() => {
if (!containerUp) {
if (translateY.value <= -50) {
scrollTo(-269);
runOnJS(setContainerUp)(true);
} else if (translateY.value >= 50) {
scrollTo(100);
} else {
scrollTo(0);
}
runOnJS(setBottomSheetSmall)(true);
} else if (containerUp) {
if (translateY.value >= -240) {
scrollTo(0);
runOnJS(setContainerUp)(false);
} else {
scrollTo(0);
}
runOnJS(setBottomSheetSmall)(false);
}
});
const rBottomSheetStyle = useAnimatedStyle(() => {
return {
transform: [{translateY: translateY.value}],
};
});
useEffect(() => {
const checkforUID = async () => {
const userUID = await AsyncStorage.getItem('UID');
if (userUID) {
console.log(userUID);
setUID(userUID);
}
};
checkforUID();
}, []);
useEffect(() => {
if (UID) {
const getProfilePicURL = async () => {
const url = await storage()
.ref(UID + 'PFP')
.getDownloadURL()
.catch(error => {
console.log(error);
const getDefaultPicURL = async () => {
const defaultURL = await storage()
.ref('circle.png')
.getDownloadURL()
.catch(error2 => {
console.log(error2);
});
setProfilePicURL(defaultURL);
console.log(url);
};
getDefaultPicURL();
});
setProfilePicURL(url);
console.log(url);
};
getProfilePicURL();
const getUserProfile = async () => {
const user = await firestore().collection('users').doc(UID).get();
setDisplayName(user._data?.displayName);
};
getUserProfile();
}
}, [UID]);
useEffect(() => {
if (UID) {
const getUserProfile = async () => {
const user = await firestore().collection('users').doc(UID).get();
setDisplayName(user._data?.displayName);
};
getUserProfile();
}
}, [UID]);
useEffect(() => {
if (displayName) {
console.log(displayName);
}
}, [displayName]);
const postComment = () => {
const currentdate = new Date();
firestore()
.collection('posts')
.doc(songID)
.collection('comments')
.add({
UID: UID,
parent: 'none',
comment: commentText,
profilePicURL: profilePicURL,
displayName: displayName,
likeAmount: 0,
hasReplies: 'no',
commentAddedAt:
currentdate.getMonth() +
1 +
'/' +
currentdate.getUTCDate() +
'/' +
currentdate.getFullYear() +
' @ ' +
currentdate.getHours() +
':' +
currentdate.getMinutes() +
':' +
currentdate.getSeconds(),
})
.then(() => {
console.log('post added!');
});
};
// get all parent comments
useEffect(() => {
if (songID) {
firestore()
.collection('posts')
.doc(songID)
.collection('comments')
.where('parent', '==', 'none')
.orderBy('likeAmount', 'desc')
.get()
.then(querySnapshot => {
console.log(querySnapshot);
setParentComments(querySnapshot._docs);
});
//re-run this effect everytime a user posts a comment
setMyComment(false);
}
}, [songID, myComment]);
// useEffect(() => {
// if (songID) {
// firestore()
// .collection('posts')
// .doc(songID)
// .collection('comments')
// .doc('ttttttttttttttttttttttt')
// .get()
// .then(querySnapshot => {
// console.log(querySnapshot);
// setParentComments(querySnapshot._docs);
// });
// //re-run this effect everytime a user posts a comment
// setMyComment(false);
// }
// }, []);
// Like a comment logic
useEffect(() => {
const increment = firebase.firestore.FieldValue.increment(1);
const minusIncrement = firebase.firestore.FieldValue.increment(-1);
if (commentID) {
if (activeLikedComments.includes(commentID)) {
setActiveLikedComments(
activeLikedComments.filter(comment => comment !== commentID),
);
firestore()
.collection('posts')
.doc(songID)
.collection('comments')
.doc(commentID)
.update({
likeAmount: minusIncrement,
});
} else {
setActiveLikedComments(current => [...current, commentID]);
try {
firestore()
.collection('posts')
.doc(songID)
.collection('comments')
.doc(commentID)
.update({
likeAmount: increment,
});
} catch (error) {
console.log(error);
}
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [likeChanged, commentID]);
useEffect(() => {
if (activeLikedComments) {
console.log(activeLikedComments);
}
}, [activeLikedComments]);
// REPLY LOGIC BELOW
const postReply = () => {
const currentdate = new Date();
firestore()
.collection('posts')
.doc(songID)
.collection('comments')
.add({
UID: UID,
parent: replyID,
comment: commentText,
profilePicURL: profilePicURL,
displayName: displayName,
likeAmount: 0,
commentAddedAt:
currentdate.getMonth() +
1 +
'/' +
currentdate.getUTCDate() +
'/' +
currentdate.getFullYear() +
' @ ' +
currentdate.getHours() +
':' +
currentdate.getMinutes() +
':' +
currentdate.getSeconds(),
})
.then(() => {
console.log('post added!');
});
firestore()
.collection('posts')
.doc(songID)
.collection('comments')
.doc(replyID)
.update({
hasReplies: 'yes',
})
.then(() => {
console.log('post added!');
});
};
const commentHandler = () => {
if (replyActive) {
postReply();
console.log('reply is true');
setReplyActive(false);
} else {
postComment();
}
};
useEffect(() => {
if (replyID) {
firestore()
.collection('posts')
.doc(songID)
.collection('comments')
.where('parent', '==', replyID)
.orderBy('likeAmount', 'desc')
.get()
.then(querySnapshot => {
console.log(querySnapshot);
setParentReplies(querySnapshot);
});
//re-run this effect everytime a user posts a comment
setMyComment(false);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [viewReplies, myComment]);
useEffect(() => {
if (parentReplies) {
console.log(parentReplies?._docs[0]?._data?.parent);
} else {
console.log('not true');
}
}, [parentReplies]);
return (
<>
<GestureDetector gesture={gesture}>
<Animated.View
style={[styles.commentContainerBackground, rBottomSheetStyle]}>
<View style={styles.drawer} />
{caption && (
<View style={styles.captionContainer}>
<View style={styles.userContainer}>
<Spotify height={15} width={15} />
<Text style={styles.username}>username</Text>
</View>
<View style={styles.captionTextContainer}>
<Text style={styles.caption}>{caption}</Text>
</View>
</View>
)}
{parentComments && (
<FlatList
// style={styles.commentFlatList}
// contentContainerStyle={{paddingBottom: '200%'}}
contentContainerStyle={
bottomSheetSmall
? {paddingBottom: '110%'}
: {paddingBottom: '160%'}
}
data={parentComments}
renderItem={({item, index}) => {
return (
<>
<View key={index} style={styles.mainContainer}>
<View style={styles.commentContainer}>
<View style={styles.commentLeftSide}>
<TouchableOpacity
onPress={() =>
navigation.navigate('ViewUserScreen', {
UID: item._data.UID,
myUID: UID,
})
}>
<Image
style={styles.userProfilePic}
source={{
uri: item._data.profilePicURL,
}}
/>
</TouchableOpacity>
<View style={styles.commentTextContainer}>
<TouchableOpacity
onPress={() =>
navigation.navigate('ViewUserScreen', {
UID: item._data.UID,
myUID: UID,
})
}>
<Text
ref={replyUsernameRef}
style={styles.userDisplayName}>
{item._data.displayName}
</Text>
</TouchableOpacity>
<Text style={styles.userComment}>
{item._data.comment}
</Text>
</View>
</View>
<View style={styles.likesContainer}>
<TouchableOpacity
onPress={() => {
setCommentID(item.id);
setMyComment(!myComment);
setLikedChanged(!likeChanged);
}}>
<Ionicons
style={styles.socialIcon}
name={
activeLikedComments.includes(item.id)
? 'heart'
: 'heart-outline'
}
color={
activeLikedComments.includes(item.id)
? Colors.red
: 'grey'
}
size={18}
/>
</TouchableOpacity>
<Text style={styles.likeText}>
{item._data.likeAmount}
</Text>
</View>
</View>
<TouchableOpacity
onPress={() => {
setReplyActive(!replyActive);
inputRef.current.focus();
setReplyUsername(item._data.displayName);
setReplyID(item.id);
}}
style={styles.replyContainer}>
<Text style={styles.replyText}>Reply</Text>
</TouchableOpacity>
{item._data.hasReplies === 'yes' && (
<TouchableOpacity
style={styles.viewRepliesContainer}
onPress={() => {
setReplyID(item.id);
setViewReplies(!viewReplies);
}}>
<Text style={styles.viewRepliesText}>
View Replies
</Text>
<Ionicons
// style={styles.socialIcon}
name={viewReplies ? 'chevron-up' : 'chevron-down'}
color={'grey'}
size={18}
/>
</TouchableOpacity>
)}
{parentReplies &&
item.id === parentReplies._docs[0]._data?.parent &&
viewReplies ? (
<>
{parentReplies._docs.map(reply => {
return (
<View
key={reply._data.id}
style={styles.repliesContainer}>
<View style={styles.repliesLeftSide}>
<Image
style={styles.repliesProfilePic}
source={{
uri: reply._data.profilePicURL,
}}
/>
<View style={styles.repliesTextContainer}>
<Text
ref={replyUsernameRef}
style={styles.repliesDisplayName}>
{reply._data.displayName}
</Text>
<Text style={styles.repliesComment}>
{reply._data.comment}
</Text>
</View>
</View>
<View style={styles.likesContainer}>
<TouchableOpacity
onPress={() => {
setCommentID(reply.id);
setMyComment(!myComment);
setLikedChanged(!likeChanged);
}}>
<Ionicons
style={styles.socialIcon}
name={
activeLikedComments.includes(reply.id)
? 'heart'
: 'heart-outline'
}
color={
activeLikedComments.includes(reply.id)
? Colors.red
: 'grey'
}
size={18}
/>
</TouchableOpacity>
<Text style={styles.likeText}>
{reply._data.likeAmount}
</Text>
</View>
</View>
);
})}
</>
) : null}
</View>
</>
);
}}
/>
)}
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 18 (1 by maintainers)
Commits related to this issue
- Fix TouchableOpacity componentDidUpdate causing an excessive number of pending callbacks (#35387) Summary: The commit https://github.com/facebook/react-native/commit/3eddc9abb70eb54209c68aab7dbd69e36... — committed to facebook/react-native by gabrieldonadel 2 years ago
- Fix TouchableOpacity componentDidUpdate causing an excessive number of pending callbacks (#35387) Summary: The commit https://github.com/facebook/react-native/commit/3eddc9abb70eb54209c68aab7dbd69e36... — committed to OlimpiaZurek/react-native by gabrieldonadel 2 years ago
I just ran into this same issue. I tracked it down to the TouchableOpacities in a few components and replaced them with Pressables, and that got rid of the error. I think the “NativeAnimatedModule” is referring to the animation on the touchableOpacity components
Yeah this seems to be caused by a change to TouchableOpacity in React Native 0.69…
https://github.com/facebook/react-native/commit/3eddc9abb70eb54209c68aab7dbd69e363cc7b29
is always going to evaluate to true, therefore calling
this._opacityInactive(250);
as many times as the component is (re)rendered.Quick fix: remove the
!== undefined
fromnode_modules/react-native/Libraries/Components/Touchable/TouchableOpacity.js
then runnpx patch-package react-native
I got the same issue in 70.5 even though It has @Girum’s fix on it. I had to change TouchcableOpacity to Pressable to solve it.
It saved my life. Thanks!
Changing all my
TouchableOpacity
toPressable
worked for me too. We thought it was to do with a bunch of promises/async awaits.For anyone interested you can create a custom
Pressable
component in Typescript that provides the same visual feedback thatTouchableOpacity
did and import and swap this wherever you usedTouchableOpacity
and not have to style eachPressable
.I change touchOpacity to Pressable, but it is not work for me.
Also encountered this using
TouchableOpacity
, might try to usePressable
instead.Update:
Using
Pressable
instead ofTouchableOpacity
removes the warning for now. Hopefully, it won’t come back. 😂await
is also a plus.That is a busy component 🙃 i don’t have a solution for you but I run into similar issues. Did you find any solution?
Thanks, solved the error for me too
@Svarto this component was being rendered inside another flatlist in another component. I just took it out of the flatlist and it worked fine. Just be careful of a lot of animated code being fired at once.