The source code of this case study is available in the
main branch of this
branch contains a few more features beyond this tutorial, such as a refined UI,
dark mode, caching with react-queries...
etc. You can try out the enhanced version right now with expo, see the
project page for instructions.
If you have any question or remarks regarding this tutorial, you're welcome in our Discord channel.
Let's get back to our
HomeScreen.tsx file. Below are the steps to get to a functional component:
- Fetch the RSS feed items. We'll do this in the
- Render a
FlatListfilled with the fetched items.
- Render individual items in a
First of all, we'll define the
FeedItem TypeScript interface in
shared-types.ts. This is the shape of items parsed by the RSS parser.
Then, let's define the hook in the
This hook uses an effect to load the feed, and store the retrieved items in a
local state (
items). A few remarks:
- We provide a
refreshfunction to trigger a new fetch along with a
- The effect callback returns a cleanup function to avoid setting state on unmounted components. Not doing this is considered an antipattern, see this guide for a deep dive.
Last but not least, if you are using TypeScript, you will need to add module
definitions for rss-parser. Put this file in the
We are going to define this component in the
components directory, like so:
This component barely displays a
FeedItem in a
Card component from
react-native-paper. Besides, it allows navigation to the "Article" route when
Since we have the data consumable with a hook, and individual items, let's
rewrite the default export of
Great! Thus you should be able to see the list on your app. Press a card and
you'll see an empty Article screen showing up. Note that we are using a
Separator component for consistent spacing above, below and between items.
If you are unfamiliar with the
FlatList component, check out the official guide.
You can drag-to-refresh the list to fetch the RSS feed again. This is thanks to
refreshing props of the
Now it's time to refine the Article screen!
To render the article, we'll need to follow the below steps:
- Fetch the HTML from the given URL;
- Parse the HTML to build a DOM;
- Extract headings from the DOM;
- Render the headings in a Drawer and the DOM in a
One important note is that we must use the explicit composite rendering
because we want access to the DOM object from the controlling component to
easily extract headings, which is more tedious when using the
implicit composite architecture (e.g., with the
Explicit composite rendering implies that we will replace
RenderHTMLSource, which will have two ascendants in the render tree: a
parents will respectively share an engine instance and configuration with any
A good place to put those providers is the very root of the application. For that end, we will
components/WebEngine.tsx and load it from
A few remarks on different props used here:
TRenderEngineConfig.ignoreDomTagsprop to ignore irrelevant tags;
TRenderEngineConfig.selectDomRootprop to select the first DOM element to render;
RenderHTMLConfig.enableExperimentalMarginCollapsingprop to collapse vertical margins.
We will go back to this component later to refine the appearance. For the time
being, we'll focus on features.
A final step is to import the
WebEngine from the root component:
Let's implement an
ArticleBody component which sole purpose is to display
the rendered DOM when it's ready, and a loading indicator when it's not:
Note that the
prop can take a
html field. Just as a reminder, we need to
dom source variant because we will have to query
headings displayed in a Drawer menu.
Back to the
We need to produce a
dom object to feed the
ArticleBody component we have
just defined. We propose two hooks to produce this object:
useFetchHtml(url: string)to fetch the HTML;
useArticleDom(url: string)to create a DOM.
Add this new file in
The important stuff is happening in the
useArticleDom hook. We're using
useAmbientTRenderEngine hook to get the
instance of the Transient Render Engine provided by
which in turns offers the
parseDocument method to
transform an HTML string into a DOM. Moreover, note that because we passed
prop to select the first
<article> met, the returned
dom object will be an
<article> element. Everything else such as
<footer> and other
elements will be ignored.
Finally, let's consume this hook from the
ArticleScreen component and render an
Fantastic! It's now rendering the whole article. It's very ugly though, and significantly divergent from the webpage layout, but we'll address that later:
We want to display a menu on the right. For this purpose, we will use the
Let's include this component in the
Now, let's get back to
useArticleDom hook and use an effect to extract headings from the DOM:
The effect is pretty straightforwards. It uses
h3 tags, and finally update the
We are now ready to define a new
TOC component to render those headings in the drawer.
Let's start by defining a
TOCEntry component in
TOCEntry renders a
Pressable which label is styled depending of the
tagName (h2 or h3) and whether it's active (e.g. selected).
Now we're ready to define the
TOC component in
Finally, we must render the
TOC component in the
Now, you should have a drawable TOC!
However, pressing an entry won't do anything. It is hence time to tackle the implementation of the tap-to-scroll feature! Let's jump to Part III.