GeekyAnts / NativeBase

Mobile-first, accessible components for React Native & Web to build consistent UI across Android, iOS and Web.
https://nativebase.io/
MIT License
20.19k stars 2.38k forks source link

Components re-render when device rotates even if breakpoint does not change #4770

Open n-harada opened 2 years ago

n-harada commented 2 years ago

Description

NativeBase components rerender unnecessarily

CodeSandbox/Snack link

https://snack.expo.dev/@n_harada/nativebasebreakpointsexample

Steps to reproduce

Open the snack on a device.

  1. See a number having been incremented at regular intervals at the center of screen.
  2. Rotate device.
  3. You can see the count incrementation stops for several seconds. (4. If you can put logger into your NativeBase code, you can see this occurs due to unnecessary re-rendering)

NativeBase Version

3.2.1

Platform

Other Platform

No response

Additional Information

NativeBase components re-render when screen size changes and break points value does not matter with this re-rendering. Even if breakpoint does not change, re-rendering occurs. It is because usePropsResolutionWithComponentTheme fires when useWindowDimensions's state changes and return value of usePropsResolutionWithComponentTheme is different object every time.

Also, ReactNative's useWindowDimensions has a bug((https://github.com/facebook/react-native/issues/29290) of which useWindowDimensions returns wrong value and the value are swapped for a very short amount of time(https://github.com/facebook/react-native/issues/29290#issuecomment-696537458).

I faced that swapping when iPad app comes to foreground. This useWindowDimensions'bug combined with NativeBase re-rendering, my app on iPad freezes several seconds every time when it comes to foreground.

I came up with two solutions about this problem with useWindowDimensions'bug.The first one is making NB components render only when value of props changes(if break point value does not change, component does not re-render even if screen size changes).The second one is to wrap useWindowDimensions for debounce to prevent re-rendering by size swapping for a very short amount of time by useWindowDimensions's bug.

Here is an example of my second solution.


import { useEffect, useRef, useState } from "react"
import { Dimensions, useWindowDimensions } from "react-native"

const debounceTime = 1000
export const useDebouncedWindowDimensions = () => {
    const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
    const [debouncedScreen, setDebouncedScreen] = useState(
        Dimensions.get("screen")
    )
    const screen = useWindowDimensions()

    useEffect(() => {
        if (timerRef.current) {
            clearTimeout(timerRef.current)
        }
        timerRef.current = setTimeout(() => {
            setDebouncedScreen(screen)
        }, debounceTime)
    }, [screen])
    return debouncedScreen
}

I love NativeBase, this library is giving me great development experience but this problem is so serious that I'm thinking about stopping using NativeBase. Hope this problem gets resolved as soon as possible.

Viraj-10 commented 2 years ago

Hi @n-harada, Thanks for reporting this issue. We will look into it.

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

OPITOs commented 2 years ago

I confirm, I have a similar problem of native-base components freezing on screen rotation, on iOS and Android.

NativeBase Version 3.3.12

AtifKhokhar commented 11 months ago

I have been working on a project and we are experiencing the same problem, it happens when we load an embedded youtube video from a react native webview go into landscape mode, this triggers the unnecessary re-render thus ruining the end user experience, could someone at NativeBase please look at a fix for this!