【问题标题】:How to allow HTML templates define React components the same as Vue?如何让 HTML 模板和 Vue 一样定义 React 组件?
【发布时间】:2019-05-11 15:18:43
【问题描述】:

在 Vue 中你可以有类似的东西。

<!-- index.php -->

<div id="app">
    <section>
        <main>
            <h1>Main</h1>
            <some-component></some-component>
        </main>
        <aside>
            <h2>Side</h2>
            <another-component></another-component>
        </aside>
    </section>
</div>

<script>
    Vue.component('some-component', { template: '<div>hello - {{ this.$parent.test }}</div>' });
    Vue.component('another-component', { template: '<div>world - {{ this.$parent.test }}</div>' });

    new Vue({el: '#app', data: () => ({test: 123})});
</script>

这将渲染所有注册的组件,你最终会得到类似的东西

<div id="app">
    <section>
        <main>
            <h1>Main</h1>
            <div>hello - 123</div>
        </main>
        <aside>
            <h2>Side</h2>
            <div>world - 123</div>
        </aside>
    </section>
</div>

如何使用 React 完成同样的事情?

我尝试过一些愚蠢的事情,比如

class App extends Component {
    render() {
        return <div>{this.props.kids}</div>
    }
}


if (document.getElementById('app')) {
    ReactDOM.render(<App kids={document.getElementById('app').innerHTML)} />, document.getElementById('app'));
}

总体目标是能够拥有普通的 html 模板,然后在需要的地方分散各种 React 组件。

理想情况下,它应该包含在一个类似无渲染的组件中,该组件可以使用上下文 api 提供向下的全局数据。

【问题讨论】:

    标签: javascript reactjs templates vue.js


    【解决方案1】:

    如果你想要类似 vue/angular 的模板,我看不出使用 React 的意义,而是使用 vue。如果你愿意,React 使用 javascript xml 或 jsx,它们看起来确实像模板,但实际上让你受益于 javascript 所能做的一切。

    虽然,如果您希望将所有内容都放在一个组件中,那么没有什么能阻止您这样做。

    现在,如果您的意思是想要一个渲染所有子组件的单个组件,那么您离 tbh 不远了。这是来自codeburst的一个简单示例

    const Picture = (props) => {
      return (
        <div>
          <img src={props.src}/>
          {props.children}
        </div>
      )
    }
    
    
    render () {
      return (
        <div className='container'>
          <Picture src={picture.src}>
              //what is placed here is passed as props.children  
          </Picture>
        </div>
      )
    }
    

    【讨论】:

    • 并不是我们想要 angular/vue 模板——而是我们不想创建一个 SPA——它需要是一个传统的 PHP 服务器端渲染的应用程序。其中少数动态组件。所以让它完全 JS 是不合适的。但是我认为您误解了-我们不“希望”将其放在单个组件中,提到的唯一原因是状态需要能够在它们之间共享。例如验证错误
    • 阅读您的其他答案,在这种情况下,您可以在任何地方使用门户。您在 return 语句之前使用 React.portal 创建的。但是,我很确定它不应该那样使用。 (但是你可以)。 reactjs.org/docs/portals.html
    【解决方案2】:

    React 不是基于模板的,而是使用 JS 或 JSX 来定义组件,所以选项有限。

    最好是

    可以使用dangerouslySetInnerHTML 渲染 HTML sn-ps:

    <div dangerouslySetInnerHTML={this.props.kids}/>
    

    这不允许在 sn-ps 中使用自定义组件,因为 React 组件不使用选择器。可以使用 HTML 解析器将模板解析为 React 元素的层次结构,然后将 &lt;some-component&gt; 等自定义元素替换为相应的 React 组件,如 this question 所示。

    可以动态定义和转换组件,但不建议在生产环境中这样做:

    <script src="https://unpkg.com/babel-standalone/babel.js"></script>
    <script src="https://unpkg.com/react/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
    <script type="text/babel">
      var Foo = () => 'Foo';
    </script>
    ...
    <script type="text/babel">
      ReactDOM.render(<Foo/>, document.getElementById('foo'));
    </script>
    

    为了将上下文 API 用于多个组件,它们不应以 render 的形式呈现为根组件,而应在一个共同的父组件中呈现,例如,以 createPortal 的门户呈现:

    ...
    <script>
      var portals = {};
    </script>
    ...
    <script type="text/babel">
      portals['#foo'] = <Foo/>;
    </script>
    ...
    <script type="text/babel">
      // runs on page load
      var CommonContext = ...;
      var Root = () => (
        <CommonContext.Provider value={...}>
          {Object.entries(portals).map(({ selector, child }) => (
            ReactDOM.createPortal(child, document.querySelector(selector))
          )}
        </CommonContext.Provider>      
      );
    
      ReactDOM.render(<Root/>, document.getElementById('root'));
    </script>
    

    【讨论】:

    • 我认为这与我试图解释的相反,我不想在 react 中呈现 HTML,我想使用 HTML 来定义要挂载的 react 组件
    • 我明白,这就是 This doesn't allow to use custom components... 所说的。您尝试做的事情与 React 应用程序的开发方式是正交的。 Vue 可以这样工作,而 React 不能。可以使用变通方法,但它们都不是直截了当的。我添加了一个如何使用 Babel 完成的示例,但我建议不要在生产中这样做。考虑在 JS 文件中开发 React 组件。如果你需要很多文件,那么你最终会得到很多文件。
    猜你喜欢
    • 2018-04-30
    • 2020-03-29
    • 1970-01-01
    • 2019-07-11
    • 2018-09-17
    • 2019-04-20
    • 2020-10-07
    • 2019-06-24
    • 2019-10-23
    相关资源
    最近更新 更多