web-dev-qa-db-ja.com

ReactでHTMLコメントをレンダリングする方法は?

現在、renderメソッドは単一の要素/コンポーネントのみを返すことができます。参照: here

そのチケットの下の議論では、HTMLコメントのReactコンポーネントから返された複数の要素をラップすることを提案しているため、ラップコンポーネントはブラウザによって無視されます。

<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コメントだけをレンダリングするコンポーネントを実際に作成する方法は?言い換えると、上記の例の「フラグメント」コンポーネントのレンダリング機能はどのように見えるのでしょうか?

19
Greg

これは、最近のプロジェクトの1つで私が終わったものです。

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>
16
Alex Zinkevych

あなたがReact 16.8+.

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>
1
Mat Lipe

これが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]-->
  ` }}
  />
}
1
briangonzalez

これを計画している方法は、単純なバニラReactソリューションでは機能しません。ただし、HTMLコメントに変換してReactラッパー内から返すカスタムWebコンポーネントを定義できます。サンプルコンポーネントが実装されています here 。 Reactでの使用法については、 this url を参照してください。

2017年1月19日更新

これは未検証の理論ですが、Webコンポーネントは次のようなものになります

/**
 * `<react-comment-sentinel>` Web Component
 *
 * @usage
   ```
   <react-comment-sentinel sentinel="fragment">
     <div>Hello there!</div>
   </react-comment-sentinel>
   ```

 * @result
   ```
   <!-- <fragment> -->
     <div>Hello there!</div>
   <!-- </fragment> -->
   ```
 */
class CommentSentinel extends HTMLElement {
  get name() {
    return 'React HTML Comment';
  }

  createdCallback() {
    /**
     * Firefox fix, is="null" prevents attachedCallback
     * @link https://github.com/WebReflection/document-register-element/issues/22
     */
    this.is = '';
    this.removeAttribute('is');
  }

  attachedCallback() {
    const tag = this.getAttribute('sentinel');

    this.outerHTML = `
      <!-- <${tag}> -->
        ${this.innerHTML}
      <!-- </${tag}> -->
    `;
  }
}

document.registerElement('react-comment-sentinel', CommentSentinel);

内側の子は、ReactではなくプレーンHTMLであることに注意してください。ただし、コードを support React Components に拡張して実験することもできます。

0
hazardous