当导航已成为焦点时更新状态

时间:2021-06-21 09:51:10

标签: javascript react-native ecmascript-6

我使用的是 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 或者是否有其他方法可以实现这一点??

提前致谢..

1 个答案:

答案 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>
    );
}