Gre*_*reg 21 javascript html5 dom reactjs react-jsx
目前,render方法只能返回单个元素/组件.见:这里
在该票据的讨论中,一些人建议将从React组件返回的多个元素包装在HTML注释中,以便浏览器忽略包装组件,例如:
<A>
<B></B>
<Fragment>
<C></C>
<D></D>
</Fragment>
<E></E>
</A>
Run Code Online (Sandbox Code Playgroud)
会呈现给:
<a>
<b></b>
<!--<fragment data-reactid="">-->
<c></c>
<d></d>
<!--</fragment>-->
<e></e>
</a>
Run Code Online (Sandbox Code Playgroud)
但是如何实际创建一个只呈现HTML注释的组件?换句话说,上面例子中'fragment'组件的render函数如何看起来像?
Ale*_*ych 16
这是我最近的一个项目中最终得到的结果:
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;
Run Code Online (Sandbox Code Playgroud)
所以你可以像这样使用它:
<A>
<B></B>
<ReactComment text="<fragment>" />
<C></C>
<D></D>
<ReactComment text="</fragment>" />
<E></E>
</A>
Run Code Online (Sandbox Code Playgroud)
ioa*_*.th 14
您可以使用以下组件来完成此操作,它简单且实用,但它的缺点是必须将注释包装在 HTML 节点(即“div”)中,因为它使用了危险的SetInnerHTML 属性:
const ReactComment = ({ text }) => {
return <div dangerouslySetInnerHTML={{ __html: `<!-- ${text} -->` }}/>
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以像这样使用它:
<ReactComment text={'My beautiful <b>HTML</b> comment'}/>
Run Code Online (Sandbox Code Playgroud)
如果您需要它与 SSR 一起使用,这是另一种新颖的方法。
这是MaxWidth我与基于 react 的电子邮件工具一起使用的组件Myza。
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]-->
` }}
/>
}
Run Code Online (Sandbox Code Playgroud)
React 中的 HTML 注释
为了在 React 中呈现注释(我猜这是大多数人在遇到这个问题时正在寻找的),我使用了一个在 gist 中的 React组件。它基于Alex Zinkevych 的答案,但进行了以下改进:
ReactDOM.findDOMNode(this),根据 React 文档,这是与 DOM 元素交互的推荐方式。我链接到了上面的要点,但我也复制了下面撰写本文时的内容,但您可能想看看要点是否有任何修订,因为我将修复我可能发现的任何错误并作为修订发布要点。
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',
}}
/>
);
}
}
Run Code Online (Sandbox Code Playgroud)
回答实际问题
然而,正如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>
)
}
Run Code Online (Sandbox Code Playgroud)
现在,我们可以将所有这些整合到一个脚本中。 这是Typescript 游乐场上的源代码,以及要点(它很大并且重复了上面详细介绍的组件,所以我不会将该代码直接复制到这个答案中。
我们可以将编译后的 JavaScript 复制到下面的代码片段中:
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',
}}
/>
);
}
}
Run Code Online (Sandbox Code Playgroud)
interface IHTMLCommentWrapperProps {
}
const HTMLCommentWrapper: React.FunctionComponent<IHTMLCommentWrapperProps> = (props) => {
return (
<React.Fragment>
<HTMLComment text={`<fragment data-reactid="">`} />
{props.children}
<HTMLComment text={`</fragment>`} />
</React.Fragment>
)
}
Run Code Online (Sandbox Code Playgroud)
如果运行此代码片段并检查 HTML,您将看到以下内容:
| 归档时间: |
|
| 查看次数: |
15969 次 |
| 最近记录: |