我在基于React的应用程序中要求渲染动态表单。表单定义存储为JSON文档,我已经有一个JS库,它解析定义并返回DocumentFragment。此库也用于其他非React应用程序,因此我无法更改它。
为了避免在我的React应用程序中重写整个逻辑来解析定义并呈现表单,我想使用现有的库。
我的问题是,在React组件中呈现DocumentFragment的最佳方法是什么?
如果我只是在render()方法中将它输出到控制台,那么这是我的DocumentFragment。
#document-fragment
<fieldset id="metadata-form-908272" class="metadata-form-rendition hide-pages">
<div class="page-header-row">
<div class="page-header-cell">
<span>[Un-named page]</span>
<button class="page-header-button button icon">
<span class="icon icon-arrow-up-11"></span></button>
</div>
</div>
<div class="page-area" id="metadata-form-page-001-area">
<div class="question-row">
<div class="question-label-cell mandatory">I have read and understood my obligations:</div>
<div class="question-input-cell">
<div class="validation-message"></div>
<label><input type="radio" value="Yes" name="metadata-form-908272-question-1">
<span>Yes</span></label>
<label><input type="radio" value="No" name="metadata-form-908272-question-1">
<span>No</span></label>
</div>
</div>
<div class="question-row">
<div class="question-label-cell">Please state all sources for the information provided:</div>
<div class="question-input-cell">
<div class="validation-message"></div>
<div class="formatted-editor">
<div class="editor-area" contenteditable="true">
<p></p>
</div>
</div>
</div>
</div>
</div>
</fieldset>
答案 0 :(得分:2)
更新:安全警报!
感谢@JaredSmith在评论中提醒,这里提供的方法 确实有安全问题。如果库不是来自您的内部,则应用它是不合适的。
要了解有关此问题的更多信息,您可以查看我在下面提到的dangerouslysetinnerhtml的链接。
这确实是实现目标的棘手方法。根据您在评论中提供的信息:
...我调用了ExternalLibrary.getFormFragment({some_data})......
导致DocumentFragments
仅在内存中,或许你知道,我们需要先将片段附加到真正的DOM元素,所以让我们创建一个根元素来追加:
let rootElement = document.createElement("div");
let frag = theExternalLibrary.getFormFragment({some_data});
rootElement.appendChild(frag);
现在我们在这里有一个纯JavaScript元素DOM树。为了将其转换为React元素,以下是涉及提供反应的方法的方式:dangerouslysetinnerhtml
你可以看到不鼓励这个方法使用它可怕的名字。
render() {
let rootElement = document.createElement("div");
let frag = theExternalLibrary.getFormFragment({some_data});
rootElement.appendChild(frag);
// rootElement.innerHTML is in string type.
return <div dangerouslySetInnerHTML={{ __html: rootElement.innerHTML }} />;
}
实例:
答案 1 :(得分:0)
我本人对此表示怀疑,因为当返回DocumentFragments时,DOMPurify和即将推出的Sanitiser API效果最好:
(data as NSString).length
function getDocumentFragment(text) {
const f = document.createDocumentFragment();
const p = document.createElement("p");
p.textContent = text;
f.appendChild(p);
return f;
}
class FragmentRenderer extends React.Component {
constructor(props) {
super(props);
this.setRef = this.setRef.bind(this);
}
setRef(ref) {
this.ref = ref;
}
componentDidMount() {
this.appendFragment();
}
componentDidUpdate(prevProps) {
if (prevProps.text != this.props.text) {
this.appendFragment();
}
}
appendFragment() {
if (!this.ref) {
return;
}
while (this.ref.firstChild) {
this.ref.removeChild(this.ref.firstChild);
}
this.ref.appendChild(getDocumentFragment(this.props.text));
}
render() {
return React.createElement("div", {
ref: this.setRef
});
}
}
ReactDOM.render(React.createElement(FragmentRenderer, {
text: "Just like this"
}), document.getElementById("app"));
因此,现在您不必转换为字符串,而不会使用angerousedSetInnerHTML,在极端情况下,由于解析问题,这可能导致您编写的元素与原始片段中的元素不同。但是,无论此片段来自何处,您仍需要信任-它不能来自用户控制的来源。 DOMPurify或Sanitizer API将是您最好的朋友。