There seems to always be vagueness to the understanding of styles in react native, as things quickly develop and change, it’s easy to lose track of these things. React Native is still exploring a lot of aspects and making important changes on how everything works.

TL; DR

  • Don’t use inline styles on pure or memoized components.
  • Just because you can use inline styles, doesn’t mean that you shouldn’t keep your code clean, code quality is important.
  • Inline styles no longer have a formidable effect on performance like before, unless you go crazy with it.

Back to the Future

If you go back to the React Native v0.55.4 and then look at the create function of the StyleSheet, then you would see something like this:

create<+S: ____Styles_Internal>(
  obj: S,
): $ObjMap<S, (Object) => StyleSheetInternalStyleIdentifier> {
  const result = {};
  for (const key in obj) {
    StyleSheetValidation.validateStyle(key, obj);
    result[key] = obj[key] && ReactNativePropRegistry.register(obj[key]);
  }
  return result;
},

ReactNativePropRegistry

Skimming through the above code block, you’ll see that it’s not a function that simply returns the stye object back to us. There is a specific call to ReactNativePropRegistry.register. Now this ReactNativePropRegistry is interesting, if we go to it’s definition, we will find that the definition has the two functions inside, register and getByID:

ReactNativePropRegistry = (function() {
  function ReactNativePropRegistry() {
    if (!(this instanceof ReactNativePropRegistry))
      throw new TypeError("Cannot call a class as a function");
  }
  ReactNativePropRegistry.register = function(object) {
    var id = ++uniqueID;
    objects[id] = object;
    return id;
  };
  ReactNativePropRegistry.getByID = function(id) {
    if (!id) return emptyObject$2;
    var object = objects[id];
    return object
      ? object
      : (console.warn("Invalid style with id `" + id + "`. Skipping ..."),
        emptyObject$2);
  };
  return ReactNativePropRegistry;
})(),

Let’s take a look at what’s going on here. If you recall, the previous code block also used the register function. With this code, every object that’s being passed into register, hence being registered as a style object, will be attached with a uniqueID. Through this uniqueID every object that’s registered will be able to be distinguished.

Now why is this important? This means that the styles are actually not kept in the component and are completely referenced from outside, which brings us to getByID. This basically lets React Native get the style object that it requires. You can see an example usage here.

0.57 Docs

The version 0.57 documentation of the StyleSheet is the final version before we are going to see the update that’s coming (which I’m also going to mention below). In this documentation we can clearly see that the performance is mentioned as an important aspect of StyleSheet.

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).

Considering everything we went through, it would make a lot of sense to strictly stick to using StyleSheet. But right after the v0.55.4, things changed a bit for styles in React Native.

Roads? Where We’re Going, We Don’t Need Roads

Let’s come back to today Marty, where we definitely need roads and where the documentation, the creation and the usage of StyleSheet has changed.

A Simple JS Object

The whole concept of saving style objects by id and holding them in a specific place like ReactNativePropRegistry is not completely gone. Instead we have this:

create<+S: ____Styles_Internal>(obj: S): $ReadOnly<S> {
  // TODO: This should return S as the return type. But first,
  // we need to codemod all the callsites that are typing this
  // return value as a number (even though it was opaque).
  if (__DEV__) {
    for (const key in obj) {
      StyleSheetValidation.validateStyle(key, obj);
      if (obj[key]) {
        Object.freeze(obj[key]);
      }
    }
  }
  return obj;
},

Now in this code block if we look outside of the if (__DEV__) condition, which would actually give us the production code would be surprisingly that nothing is happening here. We pass an object into create and that object comes back as it is. This means that it’s not that different from actually not using the create function (keep using it for other reasons like validation), but performance-wise it’s actually now no different than a regular JS object.

Latest Docs

If you go into the latest documentation on React Native website, you’d actually no longer be able to see the part about performance, instead you’d only see tips about code quality.

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.

Make no mistake, code quality is very important. Now, this is usually something to decide with your team, but separating long styles into the StyleSheet and always keeping your return as clean as possible is good for the eyes and hearts.

Recreated objects

Don’t forget, if you use inline styles the style object you added will be recreated on every render, meanwhile this is not happening with StyleSheet as it is outside of the render. This wouldn’t have a big effect as one little object doesn’t cause trouble but beware on very big projects with very big inline styles.

Re-render

I have heard many misconceptions about inline styles causing re-render all the time and this is wrong. It’s clearly stated in many blogs and posts that inline styles cause re-render for Pure and memoized components. They have no effect on regular components as regular components get re-rendered no matter what if they or their parents change props or state. I will dive into this more in my other post, but I felt this should be mentioned here as well.