当前位置: 首页 > 面试题库 >

在同构React应用中渲染HTML字符串

东方华荣
2023-03-14
问题内容

在非SPA方案中,将经过清理但随机的HTML字符串作为输入:

<p>...</p>
<p>...</p>
<gallery image-ids=""/>
<player video-id="..."/>
<p>...</p>

该字符串源自WYSIWYG编辑器,并包含嵌套的常规HTML标记和应呈现给小部件的有限数量的自定义元素(组件)。

目前,这样的HTML代码段应该分别在服务器端(Express)上呈现,但最终也将在客户端上呈现,作为同构应用程序的一部分。

我打算使用React(或类似React的框架)来实现组件,因为它大概适合这种情况-它是同构的,可以很好地呈现局部。

问题是像

<gallery image-ids="[1, 3]"/>

应该成为

<Gallery imageIds={[1, 3]}/>

JSX / TSX组件有时会出现,我不确定执行此操作的正确方法,但是我希望它是常见的任务。

如何在React中解决这种情况?


问题答案:

可以通过将html字符串解析并将生成的节点转换为React元素,将经过处理的HTML转换为可在服务器和客户端上运行的React组件。

const React = require('react');
const ReactDOMServer = require('react-dom/server');

const str = `<div>divContent<p> para 1</p><p> para 2</p><gallery image-ids="" /><player video-id="" /><p> para 3</p><gallery image-ids="[1, 3]"/></div>`;


var parse = require('xml-parser');

const Gallery = () => React.createElement('div', null, 'Gallery comp');
const Player = () => React.createElement('div', null, 'Player comp');

const componentMap = {
  gallery: Gallery,
  player: Player
};


const traverse = (cur, props) => {
  return React.createElement(
    componentMap[cur.name] || cur.name,
    props,
    cur.children.length === 0 ? cur.content: Array.prototype.map.call(cur.children, (c, i) => traverse(c, { key: i }))
  );
};

const domTree = parse(str).root;
const App = traverse(
   domTree
);

console.log(
  ReactDOMServer.renderToString(
    App
  )
);

但是请注意,您并不是真正需要的JSX / TSX,而是React渲染器的React
Nodes树(在这种情况下为ReactDOM)。JSX只是语法糖,除非您想在代码库中维护React输出,否则不需要来回转换它。

请原谅过度简化的html解析。它仅用于说明目的。您可能想使用符合规范的库来解析输入的html或适合您的用例的内容。

确保客户端捆绑软件获得完全相同的App组件,否则您可能会因为React的客户端脚本重新创建DOM树而失去服务器渲染的所有好处。

您也可以通过上述方法利用React 16的流式传输。

解决道具问题

道具将从树中作为属性提供给您,并且可以作为道具传递(在仔细考虑课程用例的情况下)。

const React = require('react');
const ReactDOMServer = require('react-dom/server');

const str = `<div>divContent<p> para 1</p><p> para 2</p><gallery image-ids="" /><player video-id="" /><p> para 3</p><gallery image-ids="[1, 3]"/></div>`;


var parse = require('xml-parser');

const Gallery = props => React.createElement('div', null, `Gallery comp: Props ${JSON.stringify(props)}`);
const Player = () => React.createElement('div', null, 'Player comp');

const componentMap = {
  gallery: Gallery,
  player: Player
};

const attrsToProps = attributes => {
  return Object.keys(attributes).reduce((acc, k) => {

    let val;
    try {
      val = JSON.parse(attributes[k])
    } catch(e) {
      val = null;
    }

    return Object.assign(
      {},
      acc,
      { [ k.replace(/\-/g, '') ]: val }
    );
  }, {});
};


const traverse = (cur, props) => {

  const propsFromAttrs = attrsToProps(cur.attributes);
  const childrenNodes = Array.prototype.map.call(cur.children, (c, i) => {

    return traverse(
      c,
      Object.assign(
        {},
        {
          key: i
        }
      )
    );
  });

  return React.createElement(
    componentMap[cur.name] || cur.name,
      Object.assign(
        {},
        props,
        propsFromAttrs
      ),
    cur.children.length === 0 ? cur.content: childrenNodes
  );
};

const domTree = parse(str).root;
const App = traverse(
  domTree
);

console.log(
  ReactDOMServer.renderToString(
    App
  )
);

但是请谨慎使用自定义属性-
您可能要遵循此rfc。如果可能,请坚持使用camelCase。



 类似资料:
  • 问题内容: 我在Wordpress页面中嵌入了一个React应用程序。它从JSON API中提取内容,并将其显示在各个区域中。 我的问题是,来自api的所有文本内容都显示为转义字符,即显示与号的位置。 我的wordpress页面通常会进行转换,但是对React内容没有影响。是因为渲染是在React中完成的吗?在哪种情况下,我需要以某种方式将React设置为使用UTF-8? 问题答案: HTML(包

  • So the great thing about React JS is that it runs on the server too. But that does not mean you can just create any app and run it on the server. You have to make some decisions on the architecture. T

  • 问题内容: 我有一个swing应用程序,该应用程序将命令发送到服务器并接收XML格式的结果。我需要通过XSLT将其转换为HTML,然后在面板上显示结果HTML。问题在于,唯一能够显示HTML的Swing组件- JEditorPane- 将URL或javax.swing.text.StyledDocument用作源。带有URL的选项对我不起作用,因为我必须先将html作为文件保存在文件系统中,并且我

  • 问题内容: 是否可以从外部源获取HTML / JSX内容并在React中动态呈现它?在我们的例子中,我们想从Wordpress API中获取内容,并在客户端和服务器上都进行渲染(我们正在使用NextJS) 因此,Wordpress API返回一个JSON响应,其中包括一个content属性,该属性是一串HTML / JSX。内容看起来像这样。 因此,如您所见,它将是HTML和React组件/ JS

  • 问题内容: 我在尝试使用数据数组呈现元素时遇到问题。在的下面的代码中,可以正常工作,但列表项未出现。 我究竟做错了什么?请随时指出并非最佳做法的任何内容。 问题答案: GoshaArinich是正确的,您应该返回您的元素。但是,在这种情况下,您应该在浏览器控制台中收到讨厌的红色警告 数组或迭代器中的每个子代都应具有唯一的“键”道具。 因此,您需要在列表中添加“键”: 或使用es6 箭头功能放下并做

  • 问题内容: 我的数据库存储产品信息,其中许多信息被组织成列表。我将数据加载到Angular中。 例如, 当我尝试将此数据加载到我的Angular应用程序中时,它会以文本形式呈现(即未解析)。我了解这可能是出于安全原因而发生的,但是有什么解决方法吗? 问题答案: 正如Damax在这里所说的那样: