First Pass

First pass at a loading indicator higher-order component

Besides the function wrapping React.PureComponent everything should look familiar. If you want to skip ahead and use this as-is, just paste this into our InfoScreen file and wrap the export:

export default withLoadingScreen(InfoScreen)

This pattern may look familiar if you’ve used Apollo or Redux before:

export default connect(mapStateToProps, mapActionCreators)(InfoScreen)

Compose

If you’re wondering how to use both connect and withLoadingScreen you can wrap the components individually or use a compose function. Writing a compose function by hand is cool, but importing the one from one of the libraries you’re already using is cooler. Both redux and react-apollo come bundled with their own:

various compose imports from redux / react-apollo

Does it work?

Depending on what your setup looks like, it might work perfectly or it might not work at all! 😃 🙃

I’m using react-navigation which supports a static method called navigationOptions to override header title and styles.

The loading screen works as intended, but the header styles are gone! What happened? Static methods aren’t copied over! It’s super easy to overlook but also super easy to fix.

There’s a library called hoist-non-react-statics that will automatically copy over static variables like navigationOptions , defaultProps and propTypes .

Second Pass: Hoisting Static Variables

Second pass at LoadingScreen higher-order component

Instead of returning the class immediately, we return it only after calling hoistNonReactStatics . The header is rendering correctly again. Woo!

Third Pass: Passing in Options

Now that the loading screen itself functions correctly, I want to pass in a different loading indicator size for different screens.

Sometimes the default loading indicator is too big or the wrong color so I’d like to be able to adjust when I need to.

connect and graphql both give you options:

connect(mapStateToProps, mapActionCreators)

graphql(MyQuery, { options })

We can do the same by adding another function call:

withNavigationOptions Higher Order Component with additional options

In this case I wanted to control the size of the ActivityIndicator

withLoadingScreen('large')(InfoScreen) // or using compose: compose(

withLoadingScreen('large'),

compose(mapStateToProps, mapActionCreators)

)(InfoScreen)

Bonus Round: Naming Your Components

You’re bound to run into issues. Sometimes the component name doesn’t show up or doesn’t match the component in question. We can fix this easily by writing a simple function called getDisplayName :

function getDisplayName(WrappedComponent) {

return (

WrappedComponent.displayName || WrappedComponent.name || "LoadingScreen"

);

}

A higher-order component with a display name

Conclusion

Higher-order components have a few weird things about them that you can fix easily. Code responsibly.

Fun things to do: