expo / router

[ARCHIVE]: Expo Router has moved to expo/expo -- The File-based router for universal React Native apps
https://docs.expo.dev/routing/introduction/
1.36k stars 113 forks source link

Expo Router v2 mounting a route twice #838

Closed shessafridi closed 1 year ago

shessafridi commented 1 year ago

Which package manager are you using? (Yarn is recommended)

npm

Summary

Expo router V2 in mounting routes twice when navigating to an outside route from a tabs screen when the tabs screen and the outside screen is in a group, this issue is not present in v1.

In the example when navigating from /my-account to /address the address/index.tsx component is mounted twice as indicated by useEffect(() => { console.log('Address Mount'); }, []); In the address/index.tsx file, this is a big issue as it also plays the routing animation twice on Android.

Removing the (first-level) group will fix the issue but in my use case I need it.

Example app folder structure:

app
│   index.tsx
│   _layout.tsx
│
└───(first-level)
    │   _layout.tsx
    │
    ├───(tabs)
    │       home.tsx
    │       my-account.tsx
    │       _layout.tsx
    │
    └───address
            index.tsx
            _layout.tsx

Minimal reproducible example

This example has a commit called "expo 49" which has the issue, and another commit called "No Issue on Expo 48" which has the project downgraded to expo router v1 with no code change

https://github.com/shessafridi/expo-router-bug

oliviercperrier commented 1 year ago

Same here

RoyalAdvisor commented 1 year ago

Also experiencing the same issue. Thought I was doing routing incorrectly.

acordiner92 commented 1 year ago

yeah same problem here

EvanBacon commented 1 year ago

This is due to a bug in React Navigation where passing the seemingly correct navigation state will cause the stack to invalidate the second screen and re-mount it. You can work around this by using React Navigation to "push" the destination screen, the caveat being that usePathname and related URL will not be correct. Here's an updated app/(first-level)/(tabs)/my-account.tsx that navigates to the screen without re-rendering.

import { View, Text } from "react-native";
import React from "react";
import { Link, useNavigation } from "expo-router";

type Props = {};

const MyAccountPage = (props: Props) => {
  const navigation = useNavigation();
  return (
    <View>
      <Text>MyAccountPage</Text>
     {/* Correct navigation + URL, but re-renders */}
      <Link href="/address">Address</Link>
     {/* Correct navigation, single render, but incorrect URL and transition. */}
      <Text
        onPress={() => {
          navigation.push("address");
        }}
      >
        Address with React Nav
      </Text>
    </View>
  );
};

export default MyAccountPage;

Also worth mentioning that nesting Stack -> Slot -> Stack may lead to problems if the nested stacks can conform to the same push events. Stacks aren't analogous to the web, if you push a page, the resolution will bubble up and may be handled in a way that makes sense technically but doesn't feel ergonomic to the developer or user.

EvanBacon commented 1 year ago

A fix has been published in expo-router@2.0.4

AyoCodess commented 1 year ago

A fix has been published in expo-router@2.0.4

thank you!

oliviercperrier commented 10 months ago

@EvanBacon In 2.0.9,

marklawlor commented 10 months ago

@oliviercperrier Please create a new issue with a reproducible demo. We cannot assist you if you don't provide any information