IjzerenHein / react-navigation-shared-element

React Navigation bindings for react-native-shared-element 💫
https://github.com/IjzerenHein/react-native-shared-element
MIT License
1.27k stars 124 forks source link

Problems while trying to update params in navigation #183

Closed Pietro-Putelli closed 3 years ago

Pietro-Putelli commented 3 years ago

Hi, I'm working to an images list using this library, but I'm not able to update the navigation params, like in the source code provided by the author, so I don't get the correct animation. Here's exactly what I mean: https://drive.google.com/file/d/1p0VZd5ODe4OYSx5_Hnq4dK8KqOwS_99F/view?usp=sharing. As you see if I open the first image and the scroll to another, when I try to dismiss the animation still occur on the first image. And here's my code:

// ImageList.js

  const renderItem = ({ item }) => {
    return (
      <TouchableOpacity
        key={`item.${item.id}`}
        onPress={() => onPressItem(item)}
      >
        <SharedElement
          id={`image.${item.id}`}
          navigation={navigation}
        >
          <Image style={styles.image} source={item.source} resizeMode="cover" />
        </SharedElement>
      </TouchableOpacity>
    );
  };

  const onPressItem = (item) => 
    navigation.push("Detail", { item });

  return (
      <FlatList
        numColumns={2}
        data={images}
        renderItem={renderItem}
        keyExtractor={(item) => item.id.toString()}
      />
  );
}

// ImageDetail.js

const DetailScreen = ({ navigation, route }) => {
  const { item, items } = route.params;

  const initialIndex = items.findIndex(({ id }) => id === item.id);

  const renderItem = ({ item }) => {
    return (
      <View key={`item.${item.id}`}>
        <SharedElement
          id={`image.${item.id}`}
          navigation={navigation}
        >
          <Image style={styles.image} source={item.source} />
        </SharedElement>
      </View>
    );
  };

  const getItemLayout = (item, index) => {
    return {
      length: width,
      offset: width * index,
      index,
    };
  };

  const onScroll = ({
    nativeEvent: {
      contentOffset: { x },
    },
  }) => {
    const index = Math.floor(x / width);
    navigation.setParams({ item: items[index] });
  };

  return (
    <View style={styles.container}>
      <FlatList
        data={items}
        horizontal
        pagingEnabled
        contentOffset={{ x: width * initialIndex }}
        renderItem={renderItem}
        onScroll={onScroll}
        getItemLayout={getItemLayout}
        keyExtractor={(item) => item.id.toString()}
      />
    </View>
  );
};

ImageDetail.sharedElements = (route) => {
  const { item } = route.params;
  return [{ id: `image.${item.id}`, animation: "move", resize: "clip" }];
};
IjzerenHein commented 3 years ago

Code looks pretty good to me (apart from ImageDetail.sharedElements which should be DetailScreen.sharedElements I think). You'll need to debug a bit to see where it's not working. Please log out the index calculated in onScroll and also log all calls to the sharedElements function in the DetailScreen component, and figure out whether those are correct.

Also please provide a fully functional example app. You may do so using https://snack.expo.dev/ or by providing a link to a test repo.

And lastly. This question/issue is about the react-navigation binding, so I'm moving this to https://github.com/IjzerenHein/react-navigation-shared-element

Pietro-Putelli commented 3 years ago

Hi Hein, thank you very much for your answer. my I've tried million of times to log the current index but always the same result! It seems that navigation.setParams don't update the params, or the SharedElement component don't reload when you pass an id that already had. Here's the expo snak code: https://snack.expo.dev/@pietroputelli/shared-element

IjzerenHein commented 3 years ago

Hey. I've had a closer look and here are my findings.

In your Snack you had out-commented setParams. This is wrong, you should enable it because the SharedElements function is also on the DetailScreen component, so accessing route.params.item will the navigation params you set on that screen.

There is a bug in onScroll. Use const index = Math.max(0, Math.floor(x / width)); to handle with scroll-overflow on iOS.

react-native-screens appears to be causing trouble in this setup. I think it is because of the FlatList on the HomeScreen, causing it to do a delay render or something like that. To workaround this, please set detachInactiveScreens={false} on the stack-navigator.

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator
        screenOptions={{ headerShown: false }}
        detachInactiveScreens={false}
      >
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen
          name="Detail"
          component={DetailScreen}
          options={sharedOptions}
        />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

I've also updated the version of react-navigation-shared-element to be the latest supported (you were still using the ancient navigation-5 branch). Please find a working version of your test-app below.

shared-element-pietro.zip

Pietro-Putelli commented 3 years ago

I don't really know how to thank you for your time. I'll send you a demo of my first app, and hope it'll be successfull! Thank you again!

On Mon, 6 Sept 2021 at 13:35, Hein Rutjes @.***> wrote:

Hey. I've had a closer look and here are my findings.

In your Snack you had out-commented setParams. This is wrong, you should enable it because the SharedElements function is also on the DetailScreen component, so accessing route.params.item will the navigation params you set on that screen.

There is a bug in onScroll. Use const index = Math.max(0, Math.floor(x / width)); to handle with scroll-overflow on iOS.

react-native-screens appears to be causing trouble in this setup. I think it is because of the FlatList on the HomeScreen, causing it to do a delay render or something like that. To workaround this, please set detachInactiveScreens={false} on the stack-navigator.

export default function App() { return (

);}

I've also updated the version of react-navigation-shared-element to be the latest supported (you were still using the ancient navigation-5 branch). Please find a working version of your test-app below.

shared-element-pietro.zip https://github.com/IjzerenHein/react-navigation-shared-element/files/7115665/shared-element-pietro.zip

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/IjzerenHein/react-navigation-shared-element/issues/183#issuecomment-913577971, or unsubscribe https://github.com/notifications/unsubscribe-auth/APL4WSIJ6JJSIMVZDM7UOSLUASRQNANCNFSM5CHJ6UJQ .