Skip to content
Logo Theodo

What's the point of StyleSheets in React Native?

Mo Khazali5 min read

A code snippet with both StyleSheets and a regular object.

Over the years, I’ve heard whispers of the mystic powers of StyleSheet.create, and how not using StyleSheet would negatively affect performance. The other day, curiosity got the better of me, and I went down a rabbit-hole of looking into the React Native source code to see if I can validate the rumours.

Starting off from the RN docs, the only benefits listed of using StyleSheet included:

Code quality tips:

By moving styles away from the render function, you’re making the code easier to understand. Naming the styles is a good way to add meaning to the low level components in the render function.

Interestingly, there used to be an additional section in docs that listed performance benefits as well:

Performance:

Making a stylesheet from a style object makes it possible to refer to it by ID instead of creating a new style object every time. It also allows to send the style only once through the bridge. All subsequent uses are going to refer an id (not implemented yet).

Looking into the source code, you surprisingly find that the create function takes in an object and returns and object (I’ve removed some of the flow types to simplify it):

  create(obj: S) {
    if (__DEV__) {
      for (const key in obj) {
        if (obj[key]) {
          Object.freeze(obj[key]);
        }
      }
    }
    return obj;
  },

There’s no reference by ID implementation here, and neither is the single pass through the bridge. Going through some diffs, it seems like before 0.66, there was validation running at runtime:

for (const key in obj) {
	StyleSheetValidation.validateStyle(key, obj);
		if (obj[key]) {
			Object.freeze(obj[key]);
		}
	}

However, this got removed since it was effectively duplicating the validation being done with prop-types. Nowadays, Typescript handles this validation for us.

So you might be asking what is the point to using StyleSheets? Some people note that it gives us Typescript typings, but you can achieve the same typechecking when you inline styles directly into a View or Text element, or just using a regular object:

// ❌ Inline Styles: Will throw an error
<View style={{ alignContent: "wrong value" }} />

// ❌ Normal Object: Also throws an error

const styles = {
  alignContent: "wrong value"
}

const MyComponent = () => (
  <View style={styles} />
) 

// ❌ StyleSheet.create: Also throws an error

const styles = StyleSheet.create({
  alignContent: "wrong value"
})

const MyComponent = () => (
  <View style={styles} />
) 

Does this mean I should just inline my styles?

You might be wondering, well in this case, should I just inline all my styles directly?

Definitely not - inlining styles has a very different result. The point I’m making here is that there is no difference when using a StyleSheet vs any other object that’s defined outside of the render function. When you inline styles, you’re instantiating objects inside the component, which means that it will be reinstantiated on every render.

I actually wanted to show this, so I created a basic test app and ran it with Flashlight to test this assumption. This app renders 6000 Views (each 1px by 1px), with 6 different colours being cycled. I ran three version of this app:

  1. Using StyleSheet.create to create the styles.
  2. Using a normal object outside the component.
  3. Inlining styles for each view.

I was looking for differences in the app startup time (effectively testing the difference in TTI). The results seemed to generally confirm the hypothesis:

Video showing the rendering of the views in each test scenario

Screenshot showing the increased average render time

The average time to startup the app (TTI) increases by around 300-400ms by using inline styles. So, there are benefits to keeping styles outside of the component itself.

So what are the actual benefits to StyleSheets?

Well, the benefits are listed loud and clear on the docs. You can clean up your render code by abstracting away the styling. This principle is very similar to the traditional web development approach of using separate CSS files that would hold your styling. In more practical terms, centralising styles and trying to reusing them across different components can help with the consistency of styling across your app, which can help you avoid the shotgun surgery problem.

Shotgun surgery is when you have to go to multiple places in your codebase and make the same change.

Source: Joe Eames (Thinkster.io)

This has an added benefit where, if you decide that you need extra styling functionality, and want to introduce a library for this down the line (like react-native-extended-stylesheets), it will make the whole refactoring process far less painful.

Lastly, more from the perspective of the library maintainers, the StyleSheet API acts as a sort of facade. If the RN team wanted to introduce additional optimisations for styling (say they wanted to flatten styles or introduce referencing by ID), they could update the implementation for StyleSheet.create and it would automatically apply to all existing apps, without requiring consumers to update their usage of RN.

Feel free to reach out

Feel free to reach out to me on Twitter @mo__javad. 🙂

Liked this article?