使用Fragment通过dangerouslySetInnerHTML插入在后端呈现的HTML

时间:2018-01-13 03:09:03

标签: node.js reactjs serverside-rendering

我曾经通过

编译和插入JSX组件
<div key={ ID } dangerouslySetInnerHTML={ { __html: HTML } } />

将我的HTML包装成<div>

<div>my html from the HTML object</div>

现在react > 16.2.0 has support for Fragments我想知道是否可以以某种方式使用它来避免每次从后端获取数据时将我的HTML包装在<div>中。

正在运行

<Fragment key={ ID } dangerouslySetInnerHTML={ { __html: HTML } } />

会发出警告

Warning: Invalid prop `dangerouslySetInnerHTML` supplied to `React.Fragment`. React.Fragment can only have `key` and `children` props.
in React.Fragment

这支持了吗?还有另一种解决方法吗?

更新

如果您想要支持它,请为其创建一个issue in the react repo

2 个答案:

答案 0 :(得分:3)

简答

不可能:

  

key是唯一可以传递给Fragment的属性。在里面   未来,我们可能会添加对其他属性的支持,例如事件   处理程序。

https://reactjs.org/docs/fragments.html

您可能想要加入并建议将其作为未来的补充。

https://github.com/facebook/react/issues

在此期间

您可能需要考虑使用HTML解析库,如:

https://github.com/remarkablemark/html-react-parser

查看此示例,了解它将如何实现您的目标:

http://remarkablemark.org/blog/2016/10/07/dangerously-set-innerhtml-alternative/

简而言之

你能够做到这一点:

<>
{require('html-react-parser')(
    '<em>foo</em>'
)}
</>

答案 1 :(得分:2)

更新2020年12月

This issue(OP也提到)已于2019年10月2日关闭。-但是,从原始问题来看,似乎RawHTML component已经进入RFC process,但没有达到生产,并且没有确定何时可以使用有效解决方案的时间表。

话虽如此,我现在想提及我目前用于解决此问题的解决方案。

在我的情况下,dangerouslySetInnerHTML用于呈现纯HTML供用户下载;在输出中包含其他包装标签并不理想。

在浏览了网络和StackOverflow之后,似乎大多数解决方案都使用了html-react-parser之类的外部库。

在此用例中, html-react-parser 不够用,因为它将HTML字符串转换为React element(s)。意思是,它将删除所有非标准JSX的HTML。


解决方案:

下面的代码是我选择使用的无库解决方案:

//HTML that will be set using dangerouslySetInnerHTML
const html = `<div>This is a div</div>`

RawHtml组件中的包装div特意命名为“ unwanteddiv”。

//Component that will return our dangerouslySetInnerHTML
//Note that we are using "unwanteddiv" as a wrapper
    const RawHtml = () => {
        return (
            <unwanteddiv key={[]}
                dangerouslySetInnerHTML={{
                    __html: html,
                }}
            />
        );
    };

在此示例中,我们将使用renderToStaticMarkup

const staticHtml = ReactDomServer.renderToStaticMarkup(
<RawHtml/>
);

神奇的地方是ParseStaticHtml函数,在这里您将了解为什么我们将包装div命名为“ unwanteddiv”。

  //The ParseStaticHtml function will check the staticHtml 
  //If the staticHtml type is 'string' 
  //We will remove "<unwanteddiv/>" leaving us with only the desired output
    const ParseStaticHtml = (html) => {
        if (typeof html === 'string') {
            return html.replace(/<unwanteddiv>/g, '').replace(/<\/unwanteddiv>/g, '');
        } else {
            return html;
        }
  };

现在,如果我们通过staticHtml函数传递ParseStaticHtml,您将看到所需的输出,而无需附加包装div:

  console.log(ParseStaticHtml(staticHtml));

此外,我还创建了一个codesandbox example来演示此操作。

注意,控制台日志将发出警告: “此浏览器无法识别标记<unwanteddiv> ...” -很好因为我们有意为它指定了唯一的名称,所以我们可以使用replace方法轻松区分和定位包装器,并在输出之前将其删除。

此外,从代码棉签中受到轻度的责骂还不如为应该更简单实现的东西增加更多的依赖关系。