“dangerouslySetInnerHTML到底有多危险?!”

需要使用dangerouslySetInnerHTML的情况。

我在React组件中写了这样的代码。

const mediaContent = getMediaContent();
return(
	<div className="post_text">
		{ mediaContent }
	</div>
)

getMediaContent()是一个用于生成显示图像等内容的HTML的原始函数。mediaContent变量存储着HTML字符串。

虽然函数生成了HTML,但并不能直接用来显示图像。它只是将字符串展示出来,而不是在浏览器中解析显示图像。

我对此感到困惑,于是向ChatGPT咨询了一下。

在JavaScript(JSX)中,如果直接呈现HTML字符串,则会以字符串的形式显示。要将字符串呈现为HTML,需要使用dangerouslySetInnerHTML属性。

const mediaContent = getMediaContent();
return(
	 <div
    	className="post_text"
      	dangerouslySetInnerHTML={{ __html: mediaContent }}
	/>
)

這樣一來,瀏覽正確無誤。然而,當我閱讀ChatGPT的回答時,對於一些可疑的屬性名稱感到有些不妥。

请注意,`dangerouslySetInnerHTML`正如其名称,存在安全风险。如果`mainText`中包含恶意脚本,则可能成为跨站脚本攻击(XSS)的目标。

嗯,只要getMediaContent()的来源明确就好。

如果出现不必要的标签,这就是一个问题。

事实上,这个故事还没有结束。接下来需要作为备忘录记录下来。

这个 dangerouslySetInnerHTML 是一个属性,所以必须与某些标签一起使用。换句话说,如果 mediaContent 生成的字符串包含了所有所需的标签,就会产生一个多余的标签。

这个多余的标签实际上是个问题。因为根据场景不同,由 mediaContent 生成的 DOM 元素会发生变化。这样就可能导致无法应用相应的 CSS。这是个大问题。

顺便提一下,可以通过引入WordPress提供的wp.element.Fragment来完成。

<Fragment 
	dangerouslySetInnerHTML={{ __html: mediaContent }} 
/>

即使这样也不行。完全没有显示出来了。

在使用html-react-parser库时的应用方法。

但是,我们有一种避免的方法。
有一个名为html-react-parser的库。
首先,使用以下命令进行安装。

npm install html-react-parser

所以,如果在React组件中写成以下这样是可以的。看起来非常清晰,不是吗?

import parse from 'html-react-parser';

// ...

return (
  <>
    {parse(mediaItem)}
  </>
);

因此,我认为使用html-react-parser是最佳选择。不过,即使使用这种方法

请注意包含不可靠的 HTML 字符串可能会带来的安全风险。如有需要,请进行适当的过滤处理。
– 来自ChatGPT的建议

在JSX中直接创建元素。

但是,根据条件可能有更简单的方法。
这种方法是直接在JSX中创建元素。
如果生成HTML的函数很复杂,就不能这样做,但是如果例如一个名为flg的状态变量为true,我们想在字符串中添加一个span标签来显示,那么可以这样做。
首先,让我们尝试一下这段代码。

const dispLabel = flg ? `${labelContent}<span>(${required.display})<span>` : labelContent;
return(
	<label>
		{dispLabel}
	</label>
)

我试图使用模板文字直接生成和渲染字符串。这样做的话,

WordPr.png

就是这样。所以

const dispLabel = flg ? `${labelContent}<span>(${required.display})<span>` : labelContent;
return(
	<label
		dangerouslySetInnerHTML={{ __html: dispLabel }}
	/>
)

如果这样做能够成功,但原本就不应该以字符串形式生成dispLabel。
因此,

const dispLabel = required.flg ? <>{labelContent}<span>({required.display})</span></> : labelContent;
return(
	<label>
		{dispLabel}
	</label>
)

这将起作用。
我会添加一点解释。
JSX(JavaScript XML)是React的一个扩展语法,它使得可以在JavaScript中编写HTML标签。

const element = <h1>Hello, world!</h1>;

当你写下这样的代码时,元素将会成为React能够理解的特殊对象。它是JavaScript对象表示的一种形式,React利用它来更新DOM。我们称之为”React元素”。
换句话说,我们只需要创建”React元素”而不是使用字符串,这样我们就能够更好地避免使用dangerouslySetInnerHTML。
这样做的好处应该是相当大的。

广告
将在 10 秒后关闭
bannerAds