Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Navigating back to a bottom tab route from a stack route that includes a PagerView causes the app to crash directly. #906

Closed
Zdadua opened this issue Nov 8, 2024 · 27 comments
Assignees
Labels
question Further information is requested

Comments

@Zdadua
Copy link

Zdadua commented Nov 8, 2024

Environment

Platform

Android

Dependencies

"react-native-pager-view": "^6.4.1",
"@react-navigation/bottom-tabs": "^6.6.1",
"@react-navigation/native": "^6.1.18",
"@react-navigation/native-stack": "^6.11.0",

Description

When I nest an A-Screen in react-navigation/native-stack, which uses react-navigation/bottom-tabs for routing, in one of the tabs of A-One-screen, I can route to an external stack screen, which we'll call B screen. If B screen uses PagerView, the app crashes when navigating to 'A-Screen' with navigation.navigate('A-Screen'). However, if PagerView is removed, everything works fine.

import {createNativeStackNavigator} from "@react-navigation/native-stack";
import TabNavigation from "./TabNavigation.tsx";
import ScorePage from "./score/ScorePage.tsx";
import {TablePage} from "./timeTable/tablePage.tsx";
import EmptyClassroomPage from "./emptyClassroom/EmptyClassroomPage.tsx";

const HomeNavigation = () => {
    const Stack = createNativeStackNavigator();

    return (
        <Stack.Navigator
            screenOptions={{
                headerShown: false,
            }}
        >
            <Stack.Screen name={'TabNavigation'} component={TabNavigation}/>
            <Stack.Screen name={'EmptyClassroomPage'} component={EmptyClassroomPage}/>
            <Stack.Screen name={'ScorePage'} component={ScorePage}/>
            <Stack.Screen name={'TablePage'} component={TablePage}/>
        </Stack.Navigator>
    )
}
const TabNavigation = () => {
    const Tab = createBottomTabNavigator();

    return (
        <Tab.Navigator
            detachInactiveScreens={false}
        >

            <Tab.Screen name={'homePage'} component={Home}/>
            <Tab.Screen name={'infoPage'} component={InfoPage}/>
        </Tab.Navigator>
    )
}

export default TabNavigation;
export interface NavigationProps {
    navigation: {
        navigate: (name: string, params?: object) => void;
        goBack: () => void;
    };
}

const Home = ({navigation}: NavigationProps) => {
    const handleNavigate = () => {
        navigation.navigate('TablePage');
    }
    return (
         <Pressable onPress={handleNavigate}></Pressable>
    )
}
const TablePage = ({navigation}: NavigationProps) => {
    const handleGoBack = () => {
        navigation.navigate('TabNavigation');
    }

    return (
         <Pressable onPress={handleGoBack}></Pressable>
         <PagerView style={{flex: 1}}>
             <View><Text style={{color: 'black'}}>123</Text></View>
         </PagerView>
    )
}
test.mp4
@Zdadua Zdadua added the question Further information is requested label Nov 8, 2024
@gelodgreat
Copy link

up for this, also experienced this issue with the new arch using RN 0.76.1

@AdrianCD101
Copy link

Yup, facing the same issue

@duongnguyen17
Copy link

same issue

@duongnguyen17
Copy link

@MrRefactor Can you check this error for us?

@MrRefactor
Copy link
Collaborator

I will check it

@MrRefactor MrRefactor self-assigned this Nov 12, 2024
@infotheme-dev
Copy link

this is a critical issue same here, can we downgrade react native (if yes which version) or any quick solution

@MrRefactor
Copy link
Collaborator

this is a critical issue same here, can we downgrade react native (if yes which version) or any quick solution

what version of react native and react-native-pager-view are you using?

@infotheme-dev
Copy link

infotheme-dev commented Nov 14, 2024

Hi all I found a solution and it's woking like charm look you have to follow one thing here : simply disable newArchEnabled=false in gradle properties, This is a problem with newArch

@infotheme-dev
Copy link

infotheme-dev commented Nov 14, 2024

"react": "18.3.1",
"react-native": "0.76.1",
"react-native-alert-notification": "^0.4.0",
"react-native-android-sms-verification-api": "^1.0.10-beta.1",
"react-native-audio-recorder-player": "^3.6.6",
"react-native-circular-progress-indicator": "^4.4.2",
"react-native-compressor": "^1.9.0",
"react-native-confirmation-code-field": "^7.3.2",
"react-native-device-info": "^14.0.0",
"react-native-eject": "^1.0.1",
"react-native-geocoding": "^0.5.0",
"react-native-geolocation-service": "^5.3.1",
"react-native-gesture-handler": "^2.20.2",
"react-native-gradle-plugin": "^0.71.19",
"react-native-image-crop-picker": "^0.41.4",
"react-native-image-zoom-viewer": "^3.0.1",
"react-native-linear-gradient": "^2.8.3",
"react-native-maps": "^1.8.0",
"react-native-modal-datetime-picker": "^17.1.0",
"react-native-pager-view": "^6.5.0",
"react-native-raw-bottom-sheet": "^2.2.0",
"react-native-reanimated": "^3.6.1",
"react-native-safe-area-context": "^4.14.0",
"react-native-screens": "^4.0.0",
"react-native-shimmer-placeholder": "^2.0.9",
"react-native-size-matters": "^0.4.2",
"react-native-snackbar": "^2.6.2",
"react-native-sound": "^0.11.2",
"react-native-splash-screen": "^3.3.0",
"react-native-svg": "^15.8.0",
"react-native-svg-transformer": "^1.1.0",
"react-native-system-navigation-bar": "^2.6.4",
"react-native-tab-view": "^3.3.0",
"react-native-video": "^5.2.1",
"react-native-webview": "^13.12.3",
"react-redux": "^8.1.3",
"redux-persist": "^6.0.0",
"redux-thunk": "^2.4.2"
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@babel/preset-env": "^7.25.3",
"@babel/runtime": "^7.25.0",
"@react-native-community/cli": "15.0.0",
"@react-native-community/cli-platform-android": "15.0.0",
"@react-native-community/cli-platform-ios": "15.0.0",
"@react-native/babel-preset": "0.76.1",
"@react-native/eslint-config": "0.76.1",
"@react-native/metro-config": "0.76.1",
"@react-native/typescript-config": "0.76.1",
"@types/react": "^18.2.6",
"@types/react-test-renderer": "^18.0.0",
"babel-jest": "^29.6.3",
"eslint": "^8.19.0",
"jest": "^29.6.3",
"prettier": "2.8.8",
"react-test-renderer": "18.3.1",
"typescript": "5.0.4"
},

But i though this is cause of newArch

@MrRefactor
Copy link
Collaborator

Hi all I found a solution and it's woking like charm look you have to follow one thing here : simply disable newArchEnabled=false in gradle properties, This is a problem with newArch

I can also see you used dependencies from my PR with bump to 76.1, did it work without disabling new arch?

@infotheme-dev
Copy link

No without disabling PR it's not working, I am also looking into Your Kotlin Files, but didn't find any thing

This is the error - java.lang.IllegalArgumentException: Scrapped or attached views may not be recycled. isScrap:false isAttached:true androidx.viewpager2.widget.ViewPager2$RecyclerViewImpl - This is from your side which is causing crash

Unhandled SoftException com.facebook.react.bridge.AssertionException: Expected to run on UI thread! from - com.swmansion.rnscreens.Screen

@ednilsoncs
Copy link

Same problem here with "react-native": "0.76.1" and "react-native-pager-view": "^6.5.0". I am using the new arc.

@infotheme-dev
Copy link

@MrRefactor This is only issue of this library, Just checked with latest version of react native screen's new update, Please check this

@ednilsoncs
Copy link

GitHub Issue: Fix for Incorrect View Removal in Recycler

Description:

After debugging this issue, I identified a possible cause and solution. The problem arises from the incorrect removal of a view during the recycling process. Specifically, the existing code does not ensure that the view is properly detached from its parent before being removed, which can lead to unexpected behavior, such as layout issues or white screens.

Current Code:

fun removeViewAt(parent: NestedScrollableHost, index: Int) {
    val pager = getViewPager(parent)
    val adapter = pager.adapter as ViewPagerAdapter?

    // Remove the child view from the adapter
    adapter?.removeChildAt(index)

    // Force a layout refresh to ensure proper rendering
    refreshViewChildrenLayout(pager)
}

Issue with Current Code:

  1. The view may still be attached to its parent when removeChildAt is called, causing inconsistencies.
  2. The refreshViewChildrenLayout does not fully address layout invalidation for the ViewPager.

Proposed Solution:

The updated code ensures:

  1. The view is detached from its parent before removal.
  2. The ViewPager is explicitly invalidated and its layout refreshed to address any remaining inconsistencies.
fun removeViewAt(parent: NestedScrollableHost, index: Int) {
    val pager = getViewPager(parent)
    val adapter = pager.adapter as ViewPagerAdapter?

    // Retrieve the child view at the specified index
    val child = adapter?.getChildAt(index)

    // Ensure the child is detached from its parent before removal
    if (child != null && child.parent != null) {
        (child.parent as? ViewGroup)?.removeView(child)
    }

    // Remove the child view from the adapter
    adapter?.removeChildAt(index)

    // Post a layout refresh to the ViewPager
    pager.post {
        pager.invalidate() // Force the view to redraw
        pager.requestLayout() // Request a new layout pass
    }
}

Why This Works:

  1. Explicitly removing the view from its parent prevents conflicts during the recycling process.
  2. Using pager.post {} ensures that layout updates are scheduled properly, avoiding potential timing issues with UI updates.

Next Steps:

  • Let me know if additional tests or validation are needed to confirm this fix.
    @MrRefactor

@ednilsoncs
Copy link

I tested this solution in my application using a fork of the project, and it worked perfectly with these changes. The issues I was experiencing were resolved, and no further problems occurred.

@MrRefactor
Copy link
Collaborator

GitHub Issue: Fix for Incorrect View Removal in Recycler

Description:

After debugging this issue, I identified a possible cause and solution. The problem arises from the incorrect removal of a view during the recycling process. Specifically, the existing code does not ensure that the view is properly detached from its parent before being removed, which can lead to unexpected behavior, such as layout issues or white screens.

Current Code:

fun removeViewAt(parent: NestedScrollableHost, index: Int) {
val pager = getViewPager(parent)
val adapter = pager.adapter as ViewPagerAdapter?

// Remove the child view from the adapter
adapter?.removeChildAt(index)

// Force a layout refresh to ensure proper rendering
refreshViewChildrenLayout(pager)

}
Issue with Current Code:

  1. The view may still be attached to its parent when removeChildAt is called, causing inconsistencies.
  2. The refreshViewChildrenLayout does not fully address layout invalidation for the ViewPager.

Proposed Solution:

The updated code ensures:

  1. The view is detached from its parent before removal.
  2. The ViewPager is explicitly invalidated and its layout refreshed to address any remaining inconsistencies.

fun removeViewAt(parent: NestedScrollableHost, index: Int) {
val pager = getViewPager(parent)
val adapter = pager.adapter as ViewPagerAdapter?

// Retrieve the child view at the specified index
val child = adapter?.getChildAt(index)

// Ensure the child is detached from its parent before removal
if (child != null && child.parent != null) {
    (child.parent as? ViewGroup)?.removeView(child)
}

// Remove the child view from the adapter
adapter?.removeChildAt(index)

// Post a layout refresh to the ViewPager
pager.post {
    pager.invalidate() // Force the view to redraw
    pager.requestLayout() // Request a new layout pass
}

}
Why This Works:

  1. Explicitly removing the view from its parent prevents conflicts during the recycling process.
  2. Using pager.post {} ensures that layout updates are scheduled properly, avoiding potential timing issues with UI updates.

Next Steps:

  • Let me know if additional tests or validation are needed to confirm this fix.
    @MrRefactor

I will check it tomorrow, thanks for help

@DrZoidberg09
Copy link

Can confirm a complete crash on Android. However, on iOS it leads to a similar issue. If you move back from the stack route and then to the stack route again, you cannot press anything in the pager view. Additionally, if you go back once again, the whole screen is frozen.

I dont know if that is related, however it is happening with the same screens as for Android, but with this behavior instead of a full crash.

@khorark
Copy link

khorark commented Nov 19, 2024

+1

This fix works for Android, but what's about iOS? Somebody know how can fix it?

@MrRefactor
Copy link
Collaborator

Please create separated issue for iOS, android merged in https://github.com/callstack/react-native-pager-view/releases/tag/v6.5.1

@duongnguyen17
Copy link

@MrRefactor i got an other issue when you fix this error:
Caused by: com.facebook.react.common.JavascriptException: Error: Exception in HostFunction: java.lang.IllegalStateException: ViewPager2 does not support direct child views

@anudit
Copy link

anudit commented Nov 20, 2024

@MrRefactor Running into this too on 6.5.1

Image

@MrRefactor
Copy link
Collaborator

Please provide repro repository.

@gelodgreat
Copy link

Thanks, @MrRefactor , This fixed my issue and running well on 0.76.1 with new arch

@duongnguyen17
Copy link

Please provide repro repository.

here is demo repo https://github.com/duongnguyen17/pager-vew-demo

@MrRefactor MrRefactor reopened this Nov 20, 2024
@radko93
Copy link

radko93 commented Nov 20, 2024

I can also confirm the issue with ViewPager2 does not support direct child views.

On paper app, no new architecture.

@radko93
Copy link

radko93 commented Nov 20, 2024

I've opened a PR for react-native-screens that fixes the last issue for me. Could not fix it inside this repo https://github.com/software-mansion/react-native-screens/pull/2527/files

@MrRefactor
Copy link
Collaborator

Please provide repro repository.

here is demo repo https://github.com/duongnguyen17/pager-vew-demo

@radko93 I have just tested ur PR on failing reproduction repo, its working fine.
For now please use patch with these changes and wait for new relase from react-native-screens Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

Successfully merging a pull request may close this issue.