arrow icon
REGISTER

Sweet Render Hijacking with React

2018-06-14
Download your copy of the
Ultimate Guide to React Native Optimization

blog content

Need help with Performance Optimization? 
hire us
Need help with Super app development
hire us
Need help with React Native?
hire us
Need help with migration to React Native?
hire us
Our React Native EU Conference is back
register nowlearn more

I’d like to share with you some obscure patterns that I’ve recently used in one of my projects. Brace yourself, because what you are about to see may hurt your eyes (or delight otherwise). For starters, let’s refresh our knowledge about Higher Order Components (HOC).

What are Higher Order Components?

In a nutshell, a HOC is just a React Component that wraps another one. Typical use cases of this would be manipulating props, abstracting state, accessing the instance via Refs or wrapping the WrappedComponent with other elements. The signature of a standard HOC is as follows:


Let’s take a look at a possible implementation for abstracting state, which could be sharing some authentication state needed by several components:

The key thing here is that the render method of the HOC returns a React Element of the type of WrappedComponent.

The use case

I recently joined a React Native project that was already under active development and got tasked with implementing some tabbed collapsible header. The Tab pages were ScrollView components at their core and were not only used under the tabs, but also in other places.

We had almost 20 of them and some needed in certain cases to be Animatable, which meant to replace the top most parent ScrollView with its animated version Animated.ScrollView and add some extra props for hooking up scroll events to animated values.

As a DRY advocate, I wanted to avoid touching all those files individually in order to set up some extra conditional logic, to either return ScrollView or Animated.ScrollView as the top most component from the render function.

Instead, I was seeking a single utility that allowed me to swap them on demand.

Can we achieve this goal with a standard HOC?

If we are familiar with the difference between components, their instances, and elements in React, you could think of creating some HOC that creates a WrappedComponent element (by calling React.createElement or using JSX) and then somehow grab its children. Something along these lines:

However, this won’t work because <WrappedComponent /> is a plain object describing a component instance and its desired propertiesIt contains only information about the component type (the displayName we used), its properties and any child elements inside it, but we can’t see beyond that.

In order to get a shallow representation of what’s WrappedComponent output, we need to call its render method.

Well…I did mention that one of the use cases of a standard HOC is accessing the instance via Refs right? Great, so you may be thinking that would allow us to control the WrappedComponent and do all sort of things with it, like calling its render.

Hold your horses cowboy.

You can access this (the instance of the WrappedComponent) with a Ref, but you will need a full initial render process of the WrappedComponentfor the ref to be calculated, that means that you need to return the WrappedComponent element from the HOC render method, let React do it’s reconciliation process and just then you will have a Ref to the WrappedComponent instance.

That means WrappedComponent will have to be already rendered on the screen, with the output that it presented initially.

Ok, we know the problem and we are getting closer to what we need. The question that needs to be asked is: is there a way to access the WrappedComponent instance before React reconciles its render output?

Let me kindly introduce you to the Inheritance Inversion HOC.

Inheritance Inversion HOC

Inheritance inversion HOC is implemented by returning a class component that extends the passed WrappedComponentinstead of React.Component. In this way the relationship between them seems inverse.


This pattern allows the HOC to have access to the WrappedComponentinstance via this, which means it has access to the state, props, component lifecycle hooks and more importantly, the render method.

Voila! Now we are able to create a HOC that can get the render tree of WrappedComponent, swap the top most parent component and keep the children intact, by using this approach.

But wait, what if our WrappedComponent is a functional (or stateless) component instead of class based? Then the call to super.render() will break our application!

We need a bit of more work to take that case into account as well. Our final and complete implementation looks as below:

Now we can finally apply this HOC to the cases where we want those scrollable components to be animatable as well.


As a side note, you should consider the below points before putting into place this solution:

  • By calling render, you get a shallow representation of the tree, hence one level deep. That means you can’t access components that are deeply nested on the tree.
  • There may be a small performance hit by calling super.render repeatedly. You could optimize by caching the result and leveraging shouldComponentUpdate to determine when to re-render.

Summary

We’ve ended up with just roughly 40 lines of code to encompass some sweet render hijacking that can be applied in the cases we need, without having to touch any of those 20 files, which would have caused incorporating and testing some extra ad-hoc logic for this particular requirement.

That means, better code maintainability, happier developers, happier myself.

This pattern may open the doors for other use cases you haven’t thought of. It’s up to your imagination and creativity.

If you wanna dive deeper into an exhaustive analysis of everything you can do with HOCs, I encourage you to check this amazing article.

If you liked this article, please recommend it to others ❤️

Author:
Raúl Gómez Acuña
arrow icon
MORE posts from this author

Bundle React Native apps using Webpack features

Discover Re.Pack – a Webpack-based toolkit that allows you to build a React Native app with the full support of the Webpack ecosystem.

learn more

More posts from this category

Ensure your React components perform as intended as your app grows

Discover Reassure - our open-source library that allows you to run performance tests measuring the average rendering time of the in-app components.

business benefits

Performance Optimization

To stay competitive, you need a high-performing app. Improving React Native performance can bring your company many business and tech benefits. To learn more about it, check the page entirely dedicated to React Native Performance Optimization. Discover a real-life example of React Native optimization we performed for Aaqua, a Singaporean platform that enables global users to share their passion through groups.

Bundle React Native apps using Webpack features

Discover Re.Pack – a Webpack-based toolkit that allows you to build a React Native app with the full support of the Webpack ecosystem.

business benefits

Why React Native?

Building an all-in-one platform can bring your company a lot of business and tech benefits like seamless UX experience, global reach, brand growth just to name a few. To learn more about the benefits of using React Native to develop super apps, check out the MoMo case study. Where we helped improve app's performance by migrating architecture to Re.Pack.

stay tuned

Subscribe to our newsletter

You may unsubscribe from these communications at any time. For details see the Privacy Policy.