我使用的是 react-native 的 createBottomTabNavigator
。当 AsyncStorage
值更新时我需要更新计数。下面是我的代码 -
function BottomTabs({ navigation }) {
const [count, setCount] = useState(0)
const checkCount = async () => {
const item = await AsyncStorage.getItem('@item_id');
const parsed = JSON.parse(item)
if (item !== null) {
const value = parsed.length;
setCount(value)
} else {
setCount(0)
}
}
useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
checkCount()
})
return unsubscribe;
}, [navigation])
return (
<Tab.Navigator>
<Tab.Screen name="My Cart" component={MyCartScreen} options={{
tabBarBadge: count,
tabBarBadgeStyle: { backgroundColor: '#1ABC9D', color: 'white', fontSize: 12, fontFamily: 'JosefinSlab-SemiBold', }
}} />
</Tab.Navigator>
);
}
上面的代码运行良好。但是当我导航到“我的购物车”屏幕并删除一些产品时,徽章计数不会更新时会出现问题。我认为这个问题是因为我在 useEffect 中使用了 focus
并且在删除产品命中时组件已经处于焦点,这就是它不会重新渲染的原因。在 React-native 中是否有其他替代方法来实现这一点而不是使用 focus
或者是否有其他方法可以实现这一点??
提前致谢..
答案 0 :(得分:1)
您应该将计数状态提升到外部并将其作为道具传递给BottomTabs。它与焦点事件无关。我认为在您的应用程序中,每次产品数量发生变化时,您都希望更新徽章编号。下面是一些代码。通常,我会使用 redux 之类的东西来实现这一点。但这里只使用事件总线模式。希望这对您有帮助。
import * as React from 'react';
import { useState, useEffect } from "react";
import { Text, View, DeviceEventEmitter, AsyncStorage, TouchableOpacity } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { MaterialCommunityIcons } from '@expo/vector-icons';
function Feed() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Feed!</Text>
<TouchableOpacity
style={{
alignItems: "center",
justifyContent: "center",
width: 200,
height: 50,
backgroundColor: "green"
}}
onPress={
() => {
DeviceEventEmitter.emit("ADD_COUNT")
}
}
>
<Text>add</Text>
</TouchableOpacity>
</View>
);
}
function Profile() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Profile!</Text>
</View>
);
}
function Notifications() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Notifications!</Text>
<TouchableOpacity
style={{
alignItems: "center",
justifyContent: "center",
width: 200,
height: 50,
backgroundColor: "green"
}}
onPress={
() => {
DeviceEventEmitter.emit("REDUCE_COUNT")
}
}
>
<Text>reduce</Text>
</TouchableOpacity>
</View>
);
}
const Tab = createBottomTabNavigator();
function MyTabs({ count }) {
return (
<Tab.Navigator
initialRouteName="Feed"
tabBarOptions={{
activeTintColor: '#e91e63',
}}
>
<Tab.Screen
name="Feed"
component={Feed}
options={{
tabBarLabel: 'Home',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="home" color={color} size={size} />
),
tabBarBadge: count
}}
listeners={({ navigation, route }) => ({
tabPress: e => {
//ga记录
DeviceEventEmitter.emit("ADD_COUNT")
},
})}
/>
<Tab.Screen
name="Notifications"
component={Notifications}
options={{
tabBarLabel: 'Updates',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="bell" color={color} size={size} />
),
}}
listeners={({ navigation, route }) => ({
tabPress: e => {
//ga记录
// onTap();
DeviceEventEmitter.emit("REDUCE_COUNT")
},
})}
/>
<Tab.Screen
name="Profile"
component={Profile}
options={{
tabBarLabel: 'Profile',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="account" color={color} size={size} />
),
}}
/>
</Tab.Navigator>
);
}
export default function App() {
const [count, setCount] = useState(0);
useEffect(() => {
AsyncStorage.getItem("count").then(_count => {
setCount(parseInt(_count ?? 0));
})
}, [])
DeviceEventEmitter.addListener("ADD_COUNT", () => {
setCount(count + 1);
AsyncStorage.setItem("count", JSON.stringify(count + 1))
})
DeviceEventEmitter.addListener("REDUCE_COUNT", () => {
setCount(count - 1)
AsyncStorage.setItem("count", JSON.stringify(count - 1))
})
return (
<NavigationContainer>
<MyTabs count={count} />
</NavigationContainer>
);
}