/* eslint-disable @typescript-eslint/no-unused-vars */
import React from 'react';
import Page from '../Page';
import RefHtmlparser2 from '../components/RefHtmlparser2';
import useToolkit from '../toolkit/useToolkit';
const minimalHtmlRenderer = `import {Text, View} from 'react-native';
import {parseDocument, ElementType} from 'htmlparser2';
import React, {PureComponent} from 'react';
export default class RenderHtml extends PureComponent {
ignoredTags = ['head'];
textTags = ['span', 'strong', 'em'];
renderTextNode(textNode, index) {
return {textNode.data};
}
renderElement(element, index) {
if (this.ignoredTags.indexOf(element.name) > -1) {
return null;
}
const Wrapper = this.textTags.indexOf(element.name) > -1 ? Text : View;
return (
{element.children.map((c, i) => this.renderNode(c, i))}
);
}
renderNode(node, index) {
switch (node.type) {
case ElementType.Text:
return this.renderTextNode(node, index);
case ElementType.Tag:
return this.renderElement(node, index);
}
return null;
}
render() {
const document = parseDocument(this.props.html);
return document.children.map((c, i) => this.renderNode(c, i));
}
}`;
export default function PageReinventTheWheel() {
const {
Acronym,
Admonition,
Bold,
Header,
Paragraph,
Chapter,
Section,
SourceDisplay,
RefLibrary,
RefRNSymbol,
RefHtmlElement,
RefCssProperty,
RefDoc,
RefRenderHtmlProp,
RenderHtmlCard,
InlineCode,
Hyperlink,
List,
ListItem,
SvgFigure
} = useToolkit();
return (
To understand how this library works, we propose a teeny, tiny
implementation of an HTML renderer in just about{' '}
40 lines of code. Of course, it has many limitations that
are overcomed by react-native-render-html,
but it will give you a good glimpse at how things work internally.
To do so, we will need an HTML parsing library which will give us some
sort of proxy DOM representation of the HTML source. In this very
example, we will use library:
Below is an overview of the component's{' '}
render method invocation:
Line 36 invokes parseDocument{' '}
from which returns the root DOM node of the
document.
Line 37 returns the mapping of the root's children with
the result of renderNode method.
Line 25, the renderNode method
returns: the result of renderTextNode when
provided with a DOM Text node, the result
of renderElement when the provided node is
an Element, and{' '}
null otherwise, such as when the provided
node is a comment, script, or stylesheet.
Although the renderTextNode implementation is
pretty straightforward,{' '}
renderElement has some conditional logic to
render the element either in a React Native{' '}
or . This is to
bypass rendering glitches when embedding {' '}
inside , such as discussed in more details
in the below section (hoisting).
We allude to the DOM an DOM nodes while only
provides a subset of the DOM API for lightweightness!
Perhaps your requirements are so simple that this might actually be
sufficient for your use-case. You could try to extend this naive
implementation with the below, easy to implement features:
Add custom renderers for specific tags such as{' '}
,
...
Add styles for specific tags and classes.
However, you will get involved in a much substantial and complex task
if you have requirements such as:{' '}
Support{' '}
inline styles
. You would need to transform those styles into React Native
compatible styles. Beware that unsupported styles on the native side
could easily crash your app.
Support{' '}
whitespace collapsing
{' '}
such as in CSS property.
Support{' '}
URL resolutions
, such as relative URLs, elements...
etc.
Support{' '}
hoisting
. Because React Native elements are not
well handled inside elements, these
should be hoisted up in the tree to be rendered inside{' '}
Views.
Support complete{' '}
CSS inheritance
. For example, a element could have a
style with text properties such as ,
but a React Native element which is the
default mapping for will not support
such style property. See page.
react-native-render-html overcomes all of
those caveats and more out of the box!
);
}