A nice use-case for React Native Portals

Cristian
Written by Cristian on
A nice use-case for React Native Portals

Some days ago we encountered a problem that seemed very time consuming to resolve it.

We’ve had the following components structure.

export const Page = () => {
	return (
		<View>
			<TopHeaderComponent/>
			<PageContent /> 
		</View>
	);
};

export const Popup = () => {
	return (
		<Popup>
			<ScrollView stickyHeaderIndices=[0]>
				<Header/>
				<Page/>
			</ScrollView>
		</Popup>
	);
};

The new requirement was that the <TopHeaderComponent/> should also be sticky and the initial idea was to move that code from <Page/> into <Header/> component, because that one was already sticky.

This was not so easy to do because that <TopHeaderComponent/> was doing a lot of logic with other components from <PageContent/> and to extract that logic would be implied to add a new set of Props and React.Context values to be able to communicate with the <Page/>.

Here is where the portals idea seemed a good solution, basically it’s a way to keep the code inside <Page/> component but you can teleport the view outside of <Page/> component in the <Header/> component.

To able to achieve this we added react-native-portal, this works well with React Native and React Native Web.

Here is an example of how to use the library:

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { Portal, PortalProvider, PortalHost } from '@gorhom/portal';

const BasicScreen = () => {
  return (
    <View style={styles.container}>
	    <Portal hostName="hostKey">
	      <Text>
	        Text to be teleported to the custom host
	      </Text>
	    </Portal>
    </View>
  );
};

const OtherScreen = () => {
	return (
		<View>
			<Stuff/>
			<PortalHost name="hostKey" />
			/* Here will go that Text component */
		</View>
	);
}

export default () => (
  <PortalProvider>
	  <NavigationContainer>
		<BasicScreen/>
	    <OtherSceen/>
	  </NavigationContainer>
  </PortalProvider>
);

Based on this example our new components structure now look like this:

export const Popup = () => {
	return (
		<Popup>
			<ScrollView stickyHeaderIndices=[0]>
				<View>
					<Header/>
					<PortalHost name="headerHostKey" />
			  </View>
				<Page/>
			</ScrollView>
		</Popup>
	)
};

and in <Page/> component we have this:

export const Page = () => {
	return (
		<View>
			<Portal hostName="headerHostKey">
				<TopHeaderComponent/>
			</Portal>
			<PageContent /> 
		</View>
	);
};

Don’t forget to wrap your app with <PortalProvider/>, this component will search in the Virtual DOM for all the active portals.

That was it, a few lines of code saved us days of refactoring!

Looking for a sharp team of developers? Let’s connect on LinkedIn!

Comments

comments powered by Disqus