I found myself recently converting a React based website which gives the user a live preview of a document they’re building while allowing them to change the content and styling of the document with ease before printing.
The preview worked really well as you could quickly style the document in a way you like and convert that preview to a PDF, then send that document off to who you need to, a huge improvement over doing that type of work in Word.
With the conversion from a React website to a React Native app I wanted to keep the preview and if possible re-use the same components used in that preview instead of porting the multitude of templates to React Native.
This approach, while tricky would allow the app to take advantage of all the templates used on the web version, as well as any additional templates that get added over time.
For my use case this works very well and means I can write one set of components for laying out a document and render it across web, app and print which makes supporting multiple platforms so much easier.
Example React Component
In order to illustrate the process I’ll create an example React component. This component would be used in a React website to layout some information the user has provided, something we want to re-use in our React Native app.
This component should live in some form of component library which can be imported into the React website, this is important as if this component is stored locally then React and React Native would have issues finding the file to import it.
Rendering React in React Native
The Webview component from react-native-webview can render a HTML string that’s passed to it via props so we’ll use this to show the component, however we can’t just pass it the component and hope it figures it out we need to convert it to HTML first.
The react-dom/server module has a function called renderToString which takes a React component and returns a HTML string, but as the component we’re working with was intended to render a sub tree in a web page it was missing the CSS definitions it was marked up to use.
You can wrap the HTML returned from the renderToString function in a HTML skeleton that adds the markup to import the CSS framework and adds the originWhitelist prop to allow the Webview to download these resources the mark up is using.
The end result is a live preview of the component’s output in a Webview that is controllable with React Native components such as TextInput .
Caveats
It’s worth pointing out that the use case for what I was doing doesn’t require real-time updates so I can’t verify that the performance of such a technique is for applications that need instantaneous updates.
Additionally, if you’re working with connected components then it’s unlikely this approach will work, however if you refactor the component to separate state and structure then you should be able to use this approach.