styled-components icon indicating copy to clipboard operation
styled-components copied to clipboard

Document React Native Performance Overhead

Open tj-mc opened this issue 2 years ago • 13 comments

Steps to reproduce

  • Create a list of items, one with items rendered normally, one with items rendered with styled-components
  • Profile the list with the flamegraph

Expected Behavior

Both render in the same time

Actual Behavior

styled-components is about 25% slower

Suggestion

Performance overhead is documented or explained somewhere that is obvious.

There is an impression that the styling happens for free or 'magically', when it really adds a notable runtime overhead. This is most obvious in long lists of items.

Many people use this package in React Native and I've worked on a few apps that have faced performance issues related to it. React Native is particularly sensitive when it comes to performance, so I think this should be explained somewhere upfront in a 'caveats' section.

tj-mc avatar Feb 03 '23 06:02 tj-mc

Totally fair, would you be up for writing it? I don't use React Native at all and am basically just keeping the lights on for the integration at this point since no other maintainers are focused on it.

quantizor avatar Mar 02 '23 05:03 quantizor

@probablyup Thanks for the response, absolutely I would. Any guidance on where this should live in the docs? FAQ perhaps?

tj-mc avatar Mar 02 '23 05:03 tj-mc

@tj-mc can you please run the same test against v6 now that it's released and let us know the outcome? Much appreciated, thanks!

efstathiosntonas avatar Jun 28 '23 06:06 efstathiosntonas

@tj-mc wondering if you ever got round to testing the latest version? Thank you for making me aware of this issue!

Bowlerr avatar Jul 10 '23 05:07 Bowlerr

Hi @efstathiosntonas and @Bowlerr 😄

I have created this reproducer to test and observe the performance differences. Included are some results from testing on my machine. When rendering 1000 empty views, I found a slowdown of 41% on v5, and 34% on v6.

That is a measurable improvement so we will upgrade our app, thank you for your work. I hope this reproducer can aid in further improving the performance.

graph

tj-mc avatar Jul 10 '23 23:07 tj-mc

Thanks @tj-mc, here are my findings on a M1 Ultra on iPhone 14 Pro Max simulator @ iOS 16.4, using expo@49 and [email protected]

|           | 1   | 2   | 3   | 4   | Avg | % Slowdown |
|-----------|-----|-----|-----|-----|-----|------------|
| Native    | 134 | 140 | 136 | 135 | 136 | 0          |
| Styled v5 | 235 | 226 | 225 | 232 | 229 | 68.38%     |
| Styled v6 | 226 | 229 | 234 | 224 | 228 | 67.65%     |

Just to make sure we're doing the same thing:

  1. Open React Dev Tools
  2. Click Profile red dot
  3. Tap the Switch to Native
  4. Wait a few secs
  5. Tap the Switch to Styled
  6. Stop the profiler
  7. Get the 224ms from the App (0.3ms of 224ms) from both commits -> StyledComponentsView and NativeStyled
  8. Reload app and profiler, repeat steps 1-8 4 times
  9. Install [email protected]
  10. Repeat 1-8 4 times

step 7 values: Screenshot 2023-07-11 at 09 46 00

The % Slowdown is the percentage difference between the Avg values.

package.json:

{
  "name": "styledcomponents",
  "version": "1.0.0",
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web"
  },
  "dependencies": {
    "expo": "~49.0.2",
    "expo-status-bar": "~1.6.0",
    "react": "18.2.0",
    "react-native": "0.72.1",
    "styled-components": "^6.0.3"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0"
  },
  "private": true
}

efstathiosntonas avatar Jul 11 '23 06:07 efstathiosntonas

That's correct @efstathiosntonas. I have tried with the exact expo versions you provided and it gave similar results. The actual numbers vary greatly depending on my machines resources but a general slowdown of at least 40-60% is measurable.

tj-mc avatar Jul 18 '23 23:07 tj-mc

@tj-mc I've created a repo with all major style libraries, just fyi: https://github.com/efstathiosntonas/react-native-style-libraries-benchmark

efstathiosntonas avatar Jul 25 '23 07:07 efstathiosntonas

Nice! @efstathiosntonas I did notice tamagui scored very poorly. It uses a compiler to optimise styles so maybe it performs better in release mode? 😃 Although, then how can we profile it 🤔 https://tamagui.dev/docs/intro/why-a-compiler#how-tamagui-helps

tj-mc avatar Jul 25 '23 13:07 tj-mc

@tj-mc I've noticed that too, I've opened a discussion about it: https://github.com/tamagui/tamagui/discussions/1471

efstathiosntonas avatar Jul 25 '23 14:07 efstathiosntonas

any updates on any improvements or suggestions on what to migrate to?

Bowlerr avatar Sep 19 '23 23:09 Bowlerr

Update to the newest version of Styled if you can. I would recommended removing as much Styled as possible and replacing it with plain RN views and StyleSheet.create. It will always be slower since it has to work all this out at runtime.

Start with components being used in any sort of list as this is where the perf impact is most noticeable.

tj-mc avatar Sep 27 '23 23:09 tj-mc

Hi all, I figured if you are watching this issue, you are trying to work out how to remove styled-components and improve app perf.

In our app, we opted to remove styled-components, since we have a very complex perf-sensitive UI, and we are not gaining much from using styled.

To assist those moving away from styled-components, I created https://github.com/tj-mc/eslint-plugin-no-styled-components

This simple rule prevents importing and/or using styled-components, which gives us better guardrails and allows us to slowly remove deprecate styled.

If this rule needs modifying for your workflow, please let me know.

tj-mc avatar Dec 18 '23 01:12 tj-mc