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.15k stars 2.38k forks source link

Slow performance compared to “pure” react-native #4302

Open vasafix opened 2 years ago

vasafix commented 2 years ago

Describe the bug I Wrote 2 lists, one using native-base components, second one using react-native components, and I am experiencing 2 to 3 times slower render on native-base side, my example consists of fairly simple list, so I wanted to ask if anyone else is experiencing similar performance issues, or for advice on what am I doing wrong or how to speed things up.

To Reproduce In my example are 2 buttons, which will navigate you to respective list, with time it took to fully transition in ms.

Expected behaviour Similar render times to react-native components.

CodeSandBox/Snack link codesandbox template

Render times in ms <html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">

  | DEV | DEV | DEV | DEV | PROD | PROD | PROD | PROD -- | -- | -- | -- | -- | -- | -- | -- | -- Native Base | Android | Android | IOS | IOS | Android | Android | IOS | IOS   | Emulator | Samsung S21 | Emulator | Iphone 13 Pro | Emulator | Samsung S21 | Emulator | Iphone 13 Pro 1 | 1103 | 319 | 266 | 188 | 605 | 255 | 208 | 150 2 | 947 | 303 | 173 | 199 | 522 | 232 | 101 | 149 3 | 966 | 339 | 163 | 191 | 615 | 236 | 94 | 150 4 | 1069 | 306 | 157 | 191 | 496 | 211 | 101 | 150 5 | 919 | 307 | 154 | 192 | 543 | 209 | 90 | 150 Avg. | 1000,8 | 314,8 | 182,6 | 192,2 | 556,2 | 228,6 | 118,8 | 149,8   |   |   |   |   |   |   |   |     | DEV | DEV | DEV | DEV | PROD | PROD | PROD | PROD React Native | Android | Android | IOS | IOS | Android | Android | IOS | IOS   | Emulator | Samsung S21 | Emulator | Iphone 13 Pro | Emulator | Samsung S21 | Emulator | Iphone 13 Pro 1 | 424 | 104 | 93 | 89 | 111 | 32 | 27 | 47 2 | 395 | 105 | 62 | 91 | 96 | 39 | 24 | 46 3 | 437 | 106 | 64 | 90 | 101 | 38 | 24 | 45 4 | 472 | 135 | 63 | 91 | 89 | 39 | 22 | 44 5 | 528 | 103 | 63 | 90 | 87 | 40 | 27 | 44 Avg. | 451,2 | 110,6 | 69 | 90,2 | 96,8 | 37,6 | 24,8 | 45,2

ezze commented 2 years ago

@vasafix Does it happen with any 3.x version?

I am experiencing an issue with 3.0.6 in Android: the more Native Base components are rendered the slower further rendering performance (i.e. when switching between visible app components). Each time I create and render a component including Native Base components I see more visible delays before my component starts to interact (run useEffect callback on mount). Seems like something is blocking event loop.

I don't see any performance issues if I switch to React Native components.

I thought that these issues might be related.

md-rehman commented 2 years ago

@vasafix have you tried our latest release because we have done a lot to fix these kinds of performance issues.

So @vasafix and @ezze, I would highly recommend both of you share your feedback on the performance of our latest version (i.e., 3.3.2).

ezze commented 2 years ago

@MD-REHMAN My issue is resolved after upgrading to 3.2.2. Unfortunately, I can't upgrade to 3.3.x at the moment because it introduces new bugs like this.

vasafix commented 2 years ago

@MD-REHMAN Can’t compare, because after updating to 3.2.2. I am now getting error:

useTheme must be used within NativeBaseConfigProvider

New snack link (native-base-3.3.2) This example is exactly same as the original one I posted, with difference of native-base version and its new dependencies @types/react and @types/react-native

vasafix commented 2 years ago

@MD-REHMAN Can’t compare, because after updating to 3.2.2. I am now getting error:

useTheme must be used within NativeBaseConfigProvider

New snack link (native-base-3.3.2) This example is exactly same as the original one I posted, with difference of native-base version and its new dependencies @types/react and @types/react-native

Seems that 3.2.4 fixed this error, I will make new render time table

fatshotty commented 2 years ago

Hi @vasafix did you try with a new render time table? I upgraded nativebase to latest version ( 3.3.7 ) but low-performance problem is still there

thanks in advance

qlereboursBS commented 2 years ago

My company and I also have performance issues A simple test can be done like this:

const TestComponent = () => {
   const [data, setData] = useState(0);
   useEffect(() => {
       const interval = setInterval(() => setData(d => d+1), 100);
       return () => clearInterval(interval);
   }, [])

   return (
       <>
           <Text>{data}</Text>
           <Button onPress={() => console.log(data)}>Click me!</Button>
       </>
   )
}

It simply rerenders every 100ms. When importing Button and Text from NativeBase, there's a latence on the button (like a few seconds), but when importing from ReactNative, or other libs like MagnusUI, there's no (or a few ms) latence. This is a stress test, but you will have the same issue with 1s rerender frequence. It's an issue which should be high priority, because it prevents to use NativeBase as a component library.

I think a good first step would be to check which component has to be optimized, to understand if it's the whole library (because of the contexts?, or the way props are computed?) or only a few components

pierroo commented 2 years ago

Unfortunately I also have to step in and confirm that as of today nativebase just isn't viable in production for android devices. I am currently undergoing the process of rewriting my whole app (which is live and distributed to millions of users...) using simple react native component; what a bummer.

If there is any plan on improving performance for android I would love to hear about it.

Wei102193 commented 2 years ago

I posted a similar issue on This. I believe the more React Native components you use the slower your app will be. Native Base is great. But this is a big issue. Most people will get rid of Native Base from their code because of it. And it is too sad that they have to rewrite their project in pure react-native if their code heavily depends on it. So read this before you dive deeply into native base. Hope they can fix this issue soon.

arunim2405 commented 2 years ago

https://snack.expo.dev/H3aB8nOYG The lag is still there and it is still significant. I have discovered this issue right before pre-production testing and I have no idea how I am going to replace these many components.

tankers746 commented 2 years ago

After doing some profiling the issue seems to lie with with this function which is called on every render of every component https://github.com/GeekyAnts/NativeBase/blob/74274d3b6bbaa49cf3731afb58027c4f8d5c22bb/src/hooks/useThemeProps/usePropsResolution.tsx#L193

Ideally this could be refactored to reduce the new object allocation.

rayan1810 commented 2 years ago

Hey folks, performance is on the top of our priority list right now, we wanted to stabilize a few things before jumping on this ship hence the delay, but be assured NativeBase will have the performance issues sorted in the upcoming weeks.

seeden commented 2 years ago

Benchmarks: https://tamagui.dev/docs/intro/benchmarks

thirteenthstep commented 2 years ago

Those benchmarks are actually quite shocking. I can confirm performance problems when navigating to new screens, where users experience a significant delay while the new screen is being rendered.

rayan1810 commented 2 years ago

The tamagui benchmark results are quite old, If I remember correctly these results were out when NativeBase v3 was initially released. But since then it has already improved significantly but yeah much more work is needed and we are already on it ✊ .

ababol commented 2 years ago

I can confirm we also have huge lag issue on Android using native-base.

Especially on list, we have to really be careful on changing a state/re-rendering list, we try not to in Android. We had to disable some feature on our app because of that.

pierroo commented 2 years ago

I can confirm we also have huge lag issue on Android using native-base.

Especially on list, we have to really be careful on changing a state/re-rendering list, we try not to in Android. We had to disable some feature on our app because of that.

Make sure to use pure/memoized component like you mentioned, but not only: when inside a list, I make sure the renderItem does not render native base component, I go back to pure react native Views and it does fix the list performance issue.

Of course this is just some temporary "hack" while waiting for native base to fix those performance issues...

ababol commented 2 years ago

@pierroo Yes, thanks a lot for the recommendation, but in our case we cannot really afford that, one of the main component of our app EventCard is written using native-base in order for us to have it working on both the app and the web, that's actually one of the main reason why we choose native-base

Rewriting this component in pure react native would probably help a lot with the performance issue (thanks a lot for the suggestion), but it would also be like dropping native-base and its benefit/why we choose it :(

Screenshot 2022-05-03 at 14 55 10
foyarash commented 2 years ago

Hello

We had the same performance issues as described in the previous comments. The issue was mostly visible on Android, but also on iOS.

We did a workaround requiring some work, but allowing us to keep a majority of native base props, by using the useStyledSystemPropsResolver hook, which is not impacted by any performance issue. By doing that we saw an improvement of more than 50% for the first render time of our most impacted screens.

Here is an example implementation for the Box component:

const Box = forwardRef<View, React.PropsWithChildren<BoxProps>>(
  ({ children, _text, safeAreaBottom, safeAreaTop, ...props }: React.PropsWithChildren<BoxProps>, ref) => {
    const [style, otherProps] = useStyledSystemPropsResolver(props);
    const { top, bottom } = useSafeAreaInsets();
    const safeAreaStyle = useMemo<StyleProp<ViewStyle>>(() => {
      const baseStyle: StyleProp<ViewStyle> = {};
      if (safeAreaBottom) {
        baseStyle.paddingBottom = bottom;
      }

      if (safeAreaTop) {
        baseStyle.paddingTop = top;
      }

      return baseStyle;
    }, [safeAreaBottom, safeAreaTop, top, bottom]);

    return (
      <View {...otherProps} style={[style, safeAreaStyle]} ref={ref}>
        {wrapStringChild(children, _text)}
      </View>
    );
  }
);

Where View is imported from react-native.

For the rest of the component, the goal was to also mimic how native-base would interact with the theme, for example for the Pressable or the Button component.

Hope this will help.

arryanggaputra commented 2 years ago

@foyarash very impressive 🔥. Have you managed to fix the Button performance issue? Can we know your implementation?

foyarash commented 2 years ago

@foyarash very impressive 🔥. Have you managed to fix the Button performance issue? Can we know your implementation?

I made a gist with the few files i used https://gist.github.com/foyarash/fa260a37fae9b085b89af13f61f46713

This worked well in our case since we don't have to handle dark mode for our app, so keep in mind that it really depends of the features you're using with native base.

antoinerousseau commented 2 years ago

@rayan1810 any progress on this? Do you need any help? If we can assist or support let us know :)

iooi commented 2 years ago

+1. I feel the lag on iOS while using NB for a couple of weeks. Really need to re-think if i need to abandon it. I am a paid customer.

frossi85 commented 2 years ago

While the issue described here is regarding Mobile, I am experiencing a similar issue using native base with NextJS. The biggest issue is observed on inputs that use text like Input and TextArea. Writing fast on the input does not provide instant feedback but takes a while between typing fast and seeing what was typed reflected in those inputs. Also, there are some slow animations. So I guess the issues are in the core and not the platform-specific implementation.

Does the team have a deadline? I am asking because started to implement something that needs to go to prod in 2 months but if the issue remains I will need to replace Nativebase.

rayan1810 commented 2 years ago

Hey folks, we are currently working on it and have already fixed components like Checkbox, we have found that the major performance issue is on Android. Currently, we are trying to resolve component theme props at boot time and inline props at runtime. I guess this will reduce the overhead on the JS Engine during runtime and give a perf boost to the App.

rayan1810 commented 2 years ago

Also for the perf issues on other Platforms apart from Android, It would be really helpful if you guys can share some code snippets and GIFs of the same.

pierroo commented 2 years ago

Hey folks, we are currently working on it and have already fixed components like Checkbox, we have found that the major performance issue is on Android. Currently, we are trying to resolve component theme props at boot time and inline props at runtime. I guess this will reduce the overhead on the JS Engine during runtime and give a perf boost to the App.

Thank you for your reply and information. Having fixed Checkbox is great for sure, but considering the hundreds of other components that needs to be fixed as well, is there any way to follow up the progress or have some kind of roadmap to better align our expectations?

Somehow, there must be some issue in the core of native base and its way of writing components, that once found out and fixed should be easily replicated overall, no?

Not gonna spoil this thread, but another easy way to see how slow the overall components are, switching from day to night mode in the app takes around 2-3 seconds, where it happens almost instantly with any other provider. Maybe this will be improved with your current work on boosting runtime?

rayan1810 commented 2 years ago

Hey @pierroo we did some experiments today, with the above mentioned idea and were able to achieve 3x better results with simple component theme resolutions. Like when you try rendering 100 Boxes with some bg and height, width it used to take ~24-26ms but now we were able to reduce it to just 8-9ms. Now we are planing to implement it properly and handle states like hover, focus, checked and so on. This is actually the most tricky part. Will try to keep you guys in loop. Also any suggestions are welcome.

PS: This makes switching color mode almost instant.

arryanggaputra commented 2 years ago

I also try to change lodash implemenation inside NativeBase with JavaScript native implementation. I got this result

Screen Shot 2022-05-10 at 03 41 57
arryanggaputra commented 2 years ago

Hi @rayan1810 , just curious... Is there any plan or update for this issue?

rayan1810 commented 2 years ago

Hey @arryanggaputra, definitely there is a plan. We are currently working on fixing this issue. The solution requires some major rewrite internally, won't break user API but we have to change a lot of things inside every component. This will take some time so we will be releasing some alpha/rc versions in the next week, you can test it out and help us fix the remaining bugs.

arunim2405 commented 2 years ago

@rayan1810 It would be great if you can divide the whole plan into small issues for the open source community to contribute to 😃

arryanggaputra commented 2 years ago

@rayan1810 hi man, any news about this issue?

Audrey-Ann commented 2 years ago

Hi @rayan1810 thank you for your help! I am also wondering if you guys are working on improving performance specifically for the Action Sheet and Buttons for Androids ? Thank you very much for your help !

rayan1810 commented 2 years ago

Hey folks, here is the Progress Update. We are working on the performance improvements and have also achieved significantly better performance metrics but it has resulted in a heavy increase in boot time load. We are currently trying to fix this by moving the same calculations to build time but due to some coupling between theme and react it's causing few issues but don't worry we have few solutions that we are trying to implement and then a rc release can be shared to test it out.

kengjungwa commented 2 years ago

Thanks a lot @rayan1810 for the update. Is this perf improvement on just Android only or also on iOS too? In my case, our iOS app performs significantly slower than Android (about 3x slower). Since we are on the critical path for releasing prod version, any updates on the progress would be really helpful for our planning.

Thanks to you and your team for working on this.

rayan1810 commented 2 years ago

Hey @kengjungwa , the performance improvements is for all the platforms but significantly focused on Android. For iOS we haven't found any such specific issues in our testings can you please share what you are facing?

kengjungwa commented 2 years ago

Hi @rayan1810 , we will try to collect the info and get back at you. Thanks in advance.

redbar0n commented 2 years ago

If it may help, I just came across this new lib which was released in May:

react-native-performance gives easy perf measurements for React Native apps.

https://github.com/Shopify/react-native-performance

mauro-codes commented 2 years ago

Hey @rayan1810, is there any rc available about this issue? Thanks in advance for all the amazing work 🙌

rayan1810 commented 2 years ago

Hola folks!! I’ve some good news for you guys 🎉 As you know, we were working on fixing the performance issues with NativeBase. Here is an update. We have an alpha version out that provides you with better runtime caching increasing your app performance by 5-6 times on subsequent renders. You can also generate a pre-resolved theme style at build time using the newly released babel plugin @native-base/babel-plugin which increases your app's performance by 2-3 times in first render and 5-6 times in subsequent renders.

Steps for getting it up and running:

yarn add native-base@3.5.0-alpha.7
yarn add -D @native-base/babel-plugin

Now add the native-base babel plugin in your -

babel.config.js:

module.exports = function (api) {
  api.cache(true);
  return {
    presets: [...YOUR_APP_PRESETS],
    plugins: ["@native-base/babel-plugin",...YOUR_OTHER_PLUGINS],
  };
};

or .babelrc:

{
    presets: [...YOUR_APP_PRESETS],
    plugins: ["@native-base/babel-plugin",...YOUR_OTHER_PLUGINS],
}

Edit: Last step is to add rm -rf .native-base in your dev script.

Something like this:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "other-scripts":"yarn something",
    "dev": "rm -rf .native-base && yarn start",
  }

Try running your Apps now and let us know your feedback.

Note: This is still in alpha stage so might have some issues with particular components.

Audrey-Ann commented 2 years ago

@rayan1810 Thank you and your team so much for your efforts !

I unfortunately ran into some issues when upgrading to 3.5.0-alpha.7 and adding the babel-plugin:

  1. When adding the babel-plugin to my babel.config.js,

    module.exports = function(api) {
    api.cache(false);
    return {
      presets: ['babel-preset-expo'],
      plugins: [
        '@native-base/babel-plugin',
        'react-native-reanimated/plugin',
        ['inline-dotenv', { path: '.env' }],
        ['module-resolver', { alias: {'@': './' } }],
      ],
    };
    };
    

    both on IOS and Android I got the following error:

    node_modules/expo/AppEntry.js: [BABEL]: Unexpected token '.' (While processing: /.../node_modules/@native-base/babel-plugin/index.js) /.../node_modules/@native-base/babel-plugin/index.js:84 bundle.resolvedStyledMap?.generatedBuildTimeMap; ^ SyntaxError: Unexpected token '.' at wrapSafe (internal/modules/cjs/loader.js:915:16) at Module._compile (internal/modules/cjs/loader.js:963:27) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10) at Module.load (internal/modules/cjs/loader.js:863:32) at Function.Module._load (internal/modules/cjs/loader.js:708:14) at Module.require (internal/modules/cjs/loader.js:887:19) at require (internal/modules/cjs/helpers.js:74:18) at loadCjsDefault (/.../node_modules/@babel/core/lib/config/files/module-types.js:100:18) at loadCjsOrMjsDefault (/.../node_modules/@babel/core/lib/config/files/module-types.js:72:16)

  2. If I comment out the "@native-base/babel-plugin" in babel.config.js and run the app, a. on IOS it loads but I get the error:

    fontFamily "Roboto" is not a system font and has not been loaded through Font.loadAsync.

    when my config is exactly like documented here.

    b. on Android, the app doesn't load at all and I get the following error message

    TypeError: undefined is not an object (evaluating 'Object.keys(object == null ? void 0 : object[providerId])') This error is located at: in NativeBaseProvider (created by App) [...]

    PS: My app uses Expo & Typescript. Here are some of the information from my package.json

    {
    [...]
    "dependencies": {
        "expo": "~45.0.6",
        "react": "17.0.2",
        "react-native": "~0.68.2",
        "native-base": "3.5.0-alpha.7",
        "babel-plugin-inline-dotenv": "^1.6.0",
        [...]
    },
    "devDependencies": {
       [...]
       "@types/react-native": "^0.67.7",
        "@babel/core": "^7.12.9",
        "@native-base/babel-plugin": "^1.0.4",
        "babel-plugin-module-resolver": "^4.1.0",
        "typescript": "^4.6.3",
    }
    }

I also tried deleting my node_modules and yarn.lock and redo a yarn install and still same errors :(

Thank you so much again in advance! Hope this is not something too difficult to solve....

rayan1810 commented 2 years ago

Thanks @Audrey-Ann for reporting this I'll be looking into this and try to release a fix as soon as possible 📦 🏃

Audrey-Ann commented 2 years ago

@rayan1810 Thank you very much ! Don't hesitate to ask me for more details if that can help too :") !

arryanggaputra commented 2 years ago

@rayan1810 thank you very much for the update. This is my error

Cannot read property 'name' of undefined
    at /Users/mpb/Project/UIProject/node_modules/@native-base/babel-plugin/index.js:173:75

babel config

const path = require("path");
const pak = require("../package.json");

module.exports = function (api) {
  api.cache(true);

  return {
    presets: ["babel-preset-expo"],
    plugins: [
      "@native-base/babel-plugin",
      [
        "module-resolver",
        {
          extensions: [".tsx", ".ts", ".js", ".json"],
          alias: {
            // For development, we want to alias the library to the source
            [pak.name]: path.join(__dirname, "..", pak.source),
          },
        },
      ],
    ],
  };
};
eytanProxi commented 2 years ago

@rayan1810 : thank you for your great work !

The performance of the version 3.5.0-alpha.7 is far better but unfortunately still too slow.

redbar0n commented 2 years ago

@eytanProxi could you quantify that?

rayan1810 commented 2 years ago

@Audrey-Ann @arryanggaputra thanks for your patience, we have fixed the babel plugin for ios and android issues in @native-base/babel-plugin version 1.0.9. But it led us to find that, the babel config is treated differently by different bundlers that is why we had to introduce a new caching folder .native-base that stores the data that the babel plugin requires to function as intended. This in turn adds one more step to the babel plugin setup. Now you have to clear this cache folder every time you run a dev build else your resolved style map will keep on increasing in size. Not sure if it makes much sense without the whole context of how we are resolving the theme at build time. But all you have to do more is to add rm -rf .native-base in your dev script.

Something like this:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "other-scripts":"yarn something",
    "dev": "rm -rf .native-base && yarn start",
  }

If you still face the issues please try deleting your node_modules and reinstalling the deps. Let me know even after that if the issue still persists.

maciejduda1 commented 2 years ago

I also found performance problems that are somewhat intensified by using nested navigation (https://reactnavigation.org/). I'm also using RN 0.69. I started building large project with it but will have to rewrite it all with my team :( since performance is not good enough for client.

Anyway. I installed the alpha version and (with rm -rf node_modules/) started my app on android. Performance is better but still first render of page with search and 25 mock results (2 small images, and some text in each of them) takes around 1,5 -2 seconds (From pressable click to navigation to page. Without NativeBase it's 0.3-0.5 s). With bigger pages results are even worse.

The one source of bigger renders is also NativeBaseProvider with custom theme. I checked ractnavigation (v. 6) + native base with RN 0.66.4, 0.64.1, 0.69. Results are similar.

Anyway i can report two errors in alpha:

  1. Slider:

    Invariant Violation: [1587,"RCTView",51,{"onStartShouldSetResponder":true,"onMoveShouldSetResponder":true,"onStartShouldSetResponderCapture":true,"onMoveShouldSetResponderCapture":true,"onResponderGrant":true,"onResponderRej
    ect":true,"onResponderRelease":true,"onResponderStart":true,"onResponderMove":true,"onResponderEnd":true,"onResponderTerminate":true,"onResponderTerminationRequest":true,"borderRadius":9999,"zIndex":999,"alignItems":"center","justif
    yContent":"center","backgroundColor":-1,"position":"absolute","width":24,"height":24,"left":"0%","transform":[{"translateX":"<<NaN>>"},{"scale":1}]}] is not usable as a native method argument
  2. Something is wrong with sizes. I mean app no longer takes full screen. I have margins from bottom (bigger) and top (smaller). Unfortunately I can't debug it in my work time so i have to leave it here.

I hope it helps! GL with improving this great project!

mohammedraoof commented 2 years ago

Hola folks!! I’ve some good news for you guys 🎉 As you know, we were working on fixing the performance issues with NativeBase. Here is an update. We have an alpha version out that provides you with better runtime caching increasing your app performance by 5-6 times on subsequent renders. You can also generate a pre-resolved theme style at build time using the newly released babel plugin @native-base/babel-plugin which increases your app's performance by 2-3 times in first render and 5-6 times in subsequent renders.

Steps for getting it up and running:

yarn add native-base@3.5.0-alpha.7
yarn add -D @native-base/babel-plugin

Now add the native-base babel plugin in your -

babel.config.js:

module.exports = function (api) {
  api.cache(true);
  return {
    presets: [...YOUR_APP_PRESETS],
    plugins: ["@native-base/babel-plugin",...YOUR_OTHER_PLUGINS],
  };
};

or .babelrc:

{
    presets: [...YOUR_APP_PRESETS],
    plugins: ["@native-base/babel-plugin",...YOUR_OTHER_PLUGINS],
}

Edit: Last step is to add rm -rf .native-base in your dev script.

Something like this:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "other-scripts":"yarn something",
    "dev": "rm -rf .native-base && yarn start",
  }

Try running your Apps now and let us know your feedback.

Note: This is still in alpha stage so might have some issues with particular components.

I used this plugin and the performance is not good enough. Hope you could fix it soon