PLEASE REPORT: Excessive number of pending callbacks: 501
See original GitHub issueDescription
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>
</>
);
}}
/>
)}
Issue Analytics
- State:
- Created a year ago
- Comments:6 (1 by maintainers)
Top GitHub Comments
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 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