I saw this beautiful bottom nav bar by Harisene (Harisene - Custom Bottom Nav Bar) and tried to implement it on my react native app.
It works fine (for some time), but at random, it crashes the app with error
unable to find viewstate for tag *** surface stopped. False
- I am using new architecture enabled
- Expo (with native build)
- Minimum reproducible repo
import AntDesign from "@expo/vector-icons/AntDesign";
import Feather from "@expo/vector-icons/Feather";
import FontAwesome6 from "@expo/vector-icons/FontAwesome6";
import Ionicons from "@expo/vector-icons/Ionicons";
import { type BottomTabBarProps } from "@react-navigation/bottom-tabs";
import { useEffect } from "react";
import { StyleSheet, TouchableOpacity, View } from "react-native";
import Animated, {
FadeIn,
FadeOut,
LinearTransition
} from "react-native-reanimated";
const AnimatedTouchableOpacity =
Animated.createAnimatedComponent(TouchableOpacity);
const PRIMARY_COLOR = "#130057";
const SECONDARY_COLOR = "#fff";
const CustomNavBar: React.FC<BottomTabBarProps> = ({
state,
descriptors,
navigation,
}) => {
return (
<View style={styles.container}>
{state.routes.map((route, index) => {
const { options } = descriptors[route.key];
const label =
options.tabBarLabel !== undefined
? options.tabBarLabel
: options.title !== undefined
? options.title
: route.name;
const isFocused = state.index === index;
const onPress = () => {
const event = navigation.emit({
type: "tabPress",
target: route.key,
canPreventDefault: true,
});
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name, route.params);
}
};
return (
<AnimatedTouchableOpacity
layout={LinearTransition.springify().mass(0.5)}
key={route.key}
onPress={onPress}
style={[
styles.tabItem,
{ backgroundColor: isFocused ? SECONDARY_COLOR : "transparent" },
]}
>
{getIconByRouteName(
route.name,
isFocused ? PRIMARY_COLOR : SECONDARY_COLOR
)}
{isFocused && (
<Animated.Text
entering={FadeIn.duration(200)}
exiting={FadeOut.duration(200)}
style={styles.text}
>
{label as string}
</Animated.Text>
)}
</AnimatedTouchableOpacity>
);
})}
</View>
);
function getIconByRouteName(routeName: string, color: string) {
switch (routeName) {
case "index":
return <Feather name="home" size={18} color={color} />;
case "orders":
return <AntDesign name="search1" size={18} color={color} />;
case "analytics":
return <Feather name="pie-chart" size={18} color={color} />;
case "sales":
return <Ionicons name="wallet-outline" size={18} color={color} />;
case "settings":
return <FontAwesome6 name="circle-user" size={18} color={color} />;
default:
return <Feather name="home" size={18} color={color} />;
}
}
};
const styles = StyleSheet.create({
container: {
position: "absolute",
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
backgroundColor: PRIMARY_COLOR,
width: "80%",
alignSelf: "center",
bottom: 10,
borderRadius: 40,
paddingHorizontal: 12,
paddingVertical: 15,
shadowColor: "#000",
shadowOffset: { width: 0, height: 5 },
shadowOpacity: 0.3,
shadowRadius: 5,
},
tabItem: {
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
height: 36,
paddingHorizontal: 13,
borderRadius: 30,
},
text: {
color: PRIMARY_COLOR,
marginLeft: 8,
fontWeight: "500",
},
});
export default CustomNavBar;
Can someone with understanding of react-native-reanimated, please assist.
PS: This is observed on Android. Havent tried on IOS