目前,render方法只能返回单个元素/组件。请参阅:here
在该票据的讨论中,一些人建议将从React组件返回的多个元素包装在HTML注释中,以便浏览器忽略包装组件,例如:
<A>
<B></B>
<Fragment>
<C></C>
<D></D>
</Fragment>
<E></E>
</A>
将渲染为:
<a>
<b></b>
<!--<fragment data-reactid="">-->
<c></c>
<d></d>
<!--</fragment>-->
<e></e>
</a>
但是如何实际创建一个只呈现HTML注释的组件?换句话说,上面例子中'fragment'组件的render函数如何看起来像?
答案 0 :(得分:15)
这是我最近的一个项目中最终得到的结果:
import React, {Component, PropTypes} from 'react';
import ReactDOM from 'react-dom';
class ReactComment extends Component {
static propTypes = {
text: PropTypes.string,
trim: PropTypes.bool
};
static defaultProps = {
trim: true
};
componentDidMount() {
let el = ReactDOM.findDOMNode(this);
ReactDOM.unmountComponentAtNode(el);
el.outerHTML = this.createComment();
}
createComment() {
let text = this.props.text;
if (this.props.trim) {
text = text.trim();
}
return `<!-- ${text} -->`;
}
render() {
return <div />;
}
}
export default ReactComment;
所以你可以像这样使用它:
<A>
<B></B>
<ReactComment text="<fragment>" />
<C></C>
<D></D>
<ReactComment text="</fragment>" />
<E></E>
</A>
答案 1 :(得分:2)
您可以使用以下组件来完成此操作,它既简单又实用,但缺点是必须将您的评论包装在 HTML 节点中,即 一个“div”,因为它使用了 risklySetInnerHTML 属性:
const ReactComment = ({ text }) => {
return <div dangerouslySetInnerHTML={{ __html: `<!-- ${text} -->` }}/>
}
然后,您可以这样使用它:
<ReactComment text={'My beautiful HTML comment'}/>
答案 2 :(得分:0)
假设您使用的是React 16.8+,则可以使用一个小的功能组件,该组件可让您提供text属性并呈现html注释。
import React, {useEffect, useRef} from 'react';
const ReactComment = ( props ) => {
const el = useRef();
useEffect( () => {
el.current.outerHTML = `<!-- ${props.text} -->`;
}, [] );
return (
<div ref={el}/>
);
};
export default ReactComment;
然后您可以像这样使用它
<A>
<B></B>
<ReactComment text="<fragment>" />
<C></C>
<D></D>
<ReactComment text="</fragment>" />
<E></E>
</A>
答案 3 :(得分:0)
如果您需要将其与SSR配合使用,则这是另一种新颖的方法。
这是我的基于反应的电子邮件工具Myza使用的MaxWidth
组件。
import ReactDOMServer from 'react-dom/server'
export const MaxWidth = ({ maxWidth = 0, className, children }: IMaxWidthProps) => {
const renderedChildren = ReactDOMServer.renderToStaticMarkup(
<div className={className} style={{ maxWidth: `${maxWidth}px`, margin: '0 auto' }}>
{children}
</div>
)
return <div dangerouslySetInnerHTML={{
__html: `
<!--[if mso]><center><table><tr><td width="${maxWidth}"><![endif]-->
${renderedChildren}
<!--[if mso]> </td></tr></table></center><![endif]-->
` }}
/>
}
答案 4 :(得分:0)
React中的HTML注释
要在React中呈现评论(这是我猜大多数人正在寻找的答案),我使用了gist中的react组件。它基于Alex Zinkevych的answer,但进行了以下改进:
ReactDOM.findDOMNode(this)
,根据React的文档,这是与DOM元素进行交互的推荐方式。我链接到上面的要点,但在以下撰写本文时,我也已复制了内容,但您可能想查看要点上是否有任何修订,因为我将修复可能发现的所有错误并作为对Gist的修订发布。
import * as React from 'react';
import * as ReactDOM from 'react-dom';
interface IProps {
text: string;
}
export class HTMLComment extends React.Component<IProps> {
private node: Comment;
private ref$rootDiv = React.createRef<HTMLDivElement>();
constructor(props: IProps) {
super(props);
this.node = window.document.createComment(props.text);
}
componentDidMount() {
if (this.ref$rootDiv && this.ref$rootDiv.current) {
let divElement = this.ref$rootDiv.current;
// Tell React not to update/control this node
ReactDOM.unmountComponentAtNode(divElement);
// Replace the div with our comment node
this.ref$rootDiv.current.replaceWith(this.node);
}
}
componentDidUpdate(prevProps: IProps) {
if (prevProps.text !== this.props.text) {
this.node.textContent = this.props.text;
}
}
componentWillUnmount() {
this.node.remove();
}
render() {
return (
<div
ref={this.ref$rootDiv}
style={{
display: 'none',
}}
/>
);
}
}
回答实际问题
但是,正如OP在对Alex的帖子的评论中指出的那样,这实际上并不能回答问题。对于在子代之前和之后呈现注释的单个组件,我们可以使用上面定义的HTMLComment组件并组成一个新组件:
interface IHTMLCommentWrapperProps {
}
const HTMLCommentWrapper: React.FunctionComponent<IHTMLCommentWrapperProps> = (props) => {
return (
<React.Fragment>
<HTMLComment text={`<fragment data-reactid="">`} />
{props.children}
<HTMLComment text={`</fragment>`} />
</React.Fragment>
)
}
现在,我们可以将所有这些放到一个脚本中。 Here is that source code在Typescript游乐场,以及Gist(很大,并且可以重复上面详细介绍的组件,因此我不会将该代码直接复制到此答案中。
我们可以将已编译的javascript复制到以下代码段中:
class HTMLComment extends React.Component {
constructor(props) {
super(props);
this.ref$rootDiv = React.createRef();
this.node = window.document.createComment(props.text);
}
componentDidMount() {
if (this.ref$rootDiv && this.ref$rootDiv.current) {
let divElement = this.ref$rootDiv.current;
// Tell React not to update/control this node
ReactDOM.unmountComponentAtNode(divElement);
// Replace the div with our comment node
this.ref$rootDiv.current.replaceWith(this.node);
}
}
componentDidUpdate(prevProps) {
if (prevProps.text !== this.props.text) {
this.node.textContent = this.props.text;
}
}
componentWillUnmount() {
this.node.remove();
}
render() {
return (React.createElement("div", { ref: this.ref$rootDiv, style: {
display: 'none',
} }));
}
}
const HTMLCommentWrapper = (props) => {
return (React.createElement(React.Fragment, null,
React.createElement(HTMLComment, { text: `<fragment data-reactid="">` }),
props.children,
React.createElement(HTMLComment, { text: `</fragment>` })));
};
const A = (props) => { return React.createElement("a", null, props.children); };
const B = (props) => { return React.createElement("b", null, props.children); };
const C = (props) => { return React.createElement("c", null, props.children); };
const D = (props) => { return React.createElement("d", null, props.children); };
const E = (props) => { return React.createElement("e", null, props.children); };
const App = () => {
return (React.createElement(A, null,
React.createElement(B, null),
React.createElement(HTMLCommentWrapper, null,
React.createElement(C, null),
React.createElement(D, null)),
React.createElement(E, null)));
};
let el$root = document.getElementById('react-app');
if (el$root) {
ReactDOM.render(React.createElement(App, null), el$root);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="react-app"/>
如果运行此代码段并检查HTML,则会看到以下内容:
答案 5 :(得分:0)
创建一个文件名为 Comment.js 的函数式组件
结合使用原生 javascript document.createComment 导入 jquery 以使用它们的类选择器来选择 div
使用 props 传递要在评论中使用的文本,以及要选择的 div 的名称:
import $ from 'jquery';
const Comment = (props) => {
const commentMakerBegin = () => {
setTimeout(() => {
const beginComment = document.createComment(props.beginComment);
const firstElement = $('.' + props.beforeDiv);
firstElement.before(beginComment);
}, 1000);
};
const commentMakerEnd = (event) => {
setTimeout(() => {
const endComment = document.createComment(props.endComment);
const secondElement = $('.' + props.afterDiv);
secondElement.after(endComment);
}, 1000);
};
return (
<>
{commentMakerBegin()}
{props.children}
{commentMakerEnd()}
</>
);
};
export default Comment;
props.children 渲染自定义组件标签之间的任何内容:
{props.children}
无论您输入“您的组件在此”还是“<C /><D />
”这样的字符串,它都会在开始和结束标记之间呈现您输入的内容。
在您要使用新创建的 Comment 组件的组件中,导入它,然后通过您要用于开始和结束评论的 props 传递文本
下图是我在两个模态(分别是消费者模态和策略模态)之前和之后呈现评论的方式。
在我的 App.js 文件中,我导入了 Comments 组件并按以下方式使用它,结果是上述屏幕截图:
<Comment
beforeDiv='consumer-modal'
afterDiv='policy-modal'
beginComment='modal begins'
endComment='modal ends'
>
<ConsumerModal
title='testing'
content={<ConsumerModalContent />}
onClose={cnsmrModalHandler}
></ConsumerModal>
<PolicyModal
title='my policy'
content={<PolicyModalContent />}
onClose={policyModalHandler}
/>
</Comment>
答案 6 :(得分:-4)
修改:对于发现此答案有用的人,请结帐this answer!
发布的问题不是在React中要求评论样式!
使用大括号,以便您可以使用javascript comment /* */
。
<a>
<b></b>
{/*<fragment data-reactid="">*/}
<c></c>
<d></d>
{/*</fragment>*/}
<e></e>
</a>