dominicstop / react-native-ios-context-menu

A react-native component to use context menu's (UIMenu) on iOS 13/14+
MIT License
572 stars 29 forks source link

ContextMenuView doesn't re-render properly on tab navigation #65

Open PierrotAWB opened 1 year ago

PierrotAWB commented 1 year ago

First, thanks to those who've worked on this library. Aside from this singular problem, it's been a pleasure working in it.

I'm facing an issue which is similar to, but as far as I can tell, distinct from #34.

The goal is to implement a 'like' button on a ContextMenuView. Each time the button's clicked, it toggles a state variable and the UI should update accordingly. This change should persist even as the menu's hidden (if I 'like', then hide the menu and open it again, it should still indicate that I've 'liked').

I've produced a minimal example to illustrate the problem: although the button works initially, as soon as I navigate to another tab and back, it stops re-rendering properly. Both the UI and a console.log() I've included in the code indicate that the state variable (favourite) holds the correct value at all times. The issue is that it's no longer the case that clicking 'like' is immediately reflected in the UI (the menu does not re-render properly).


import React, {useState} from 'react';
import { Text, View, TouchableOpacity, Button, StyleSheet } from 'react-native';
import { ContextMenuView } from 'react-native-ios-context-menu';
import {
  NavigationContainer, useFocusEffect,
} from '@react-navigation/native';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';

const Tab = createBottomTabNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="First" component={Tab1} />
        <Tab.Screen name="Second" component={Tab2} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

function Tab1({ navigation }) {
  const [favourite, setFavourite] = useState(false);

  useFocusEffect(() => {
    console.log(`Current value of favourite: ${favourite}`);
  });

  const toggleFavourite = () => {
    setFavourite((prev) => !prev);
  }

  return (
    <TouchableOpacity
      style={styles.container}
      onPress={async () => { navigation.navigate("Second") }}
    >
      <ContextMenuView
        style={{
          backgroundColor: "white",
          width: "100%",
          alignItems: "center",
        }}
        useActionSheetFallback={false}
        onPressMenuItem={({ nativeEvent }) => {
          console.log("nativeEvent: ", nativeEvent);
          switch (nativeEvent.actionKey) {
            case "HEART":
              toggleFavourite();
              break;
          }
        }}
        menuConfig={{
          menuTitle: "",
          menuItems: [
            {
              actionKey: "HEART",
              actionTitle: `${favourite ? "Unlike" : "Like"}`,
              menuAttributes: ['keepsMenuPresented'],
              icon: {
                type: "IMAGE_SYSTEM",
                imageValue: {
                    systemName: (favourite
                  ? 'heart.fill'
                  : 'heart'
                ),
                },
              },
            },
          ],
        }}
      >
      <View style={{height: 100, justifyContent: "center"}}>
        <Text style={{fontSize: 14}} numberOfLines={2}>
          Hold to pop out!
        </Text>
      </View>
      </ContextMenuView>
    </TouchableOpacity>
  );
}

function Tab2({navigation}) {
  return (
    <View style={{ flex: 1, justifyContent: "center"}}>
      <Button title="Go back" onPress={() => navigation.navigate("First")} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flexDirection: "row",
    justifyContent: "center",
    width: "100%",
  }
});

https://github.com/dominicstop/react-native-ios-context-menu/assets/20756534/dc9e42e5-0a76-47c8-9c0c-81cc27e89ccc


Environment:

dominicstop commented 1 year ago

hi, thank you for submitting an issue; i’ll try to debug this in the weekend ahakhskdkffkfjl

this might be (another) bug with the cleanup logic, or maybe the changes to the menuConfig prop is not being detected?

hopefully, it’s not too hard to fix

nandorojo commented 1 year ago

It's possible this is due to react-freeze. I wonder if toggling enableFreeze from react-native-screens changes anything.

nandorojo commented 1 year ago

@PierrotAWB can you try adding this to the child of the context menu:

<Pressable delayLongPress={100} onLongPress={() => {}}>
  {child}
</Pressable>