具有客户端和服务器端渲染的React同构组件

3
我希望创建一个同时具有客户端和服务器端渲染的React应用程序。
以下是示例:
import styles from './Main.css';

import React, {Component} from 'react';
import Info from './Info/Info';
import Record from './Record/Record'

export default class Main extends Component {
    render() {
        return (
            <div className={styles.main}>
                <div className={styles.mainIn + ' clearfix'}>
                    <div className={styles.mainLeft}>
                        <Info info_num="2012201972"/>
                    </div>
                    <div className={styles.mainRight}>
                        <div className="clearfix mb20">
                            <Record />
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}

在这个组件 Main 中,需要在客户端进行渲染,除了<Record />
组件Record
import styles from './Record.css';
import layout from '../../shared/styles/layout.css'

import React, {Component} from 'react';

export default class Record extends Component {
    render() {
        return (
            <div className="float_two">
                <div className={layout.box + ' mr10'}>
                    This is Record!
                </div>
            <div>
        )
    }
}

这是我的问题:
我查找了一些使用 ReactDom.renderToStringreact-router 进行服务器端渲染的示例。然而,没有同时包含客户端和服务器端渲染的教程。
我想要实现的目标是,客户端首先加载和呈现组件 <Main />,然后从服务器端加载 <Record />
另一个问题是,如何使用 renderToString 加载样式模块 Record.css,因为我认为在这个 renderToString 中只能加载 HTML 而不能加载 CSS。
2个回答

2
当人们提到服务器端渲染时,通常是指在某个路由下的顶层应用程序的初始渲染,而不是单个组件。
我不太明白你的请求是什么用例。你的React应用程序是一个大的Fragments树,因此单独渲染单个组件并没有什么意义。如果你想要Record成为React的一部分,那么客户端将需要知道它,所以为什么不像通常情况下那样在客户端上呈现它呢?
如果你真的需要在服务器端呈现它,那么我猜你可以构建Record组件,让它执行AJAX请求,然后使用https://facebook.github.io/react/tips/dangerously-set-inner-html.html来呈现返回的HTML,但我不会推荐这样做。
我猜测Record需要从服务器端获取某种数据,这就是你想要在服务器端呈现它的原因?相反,只需作为JSON获取该数据,并使用该数据在客户端上渲染该组件即可。
阅读了你的评论,我知道你试图做什么。你想要的是根据某些事件(滚动,按钮单击或其他)从服务器动态加载内容(而不是呈现的HTML)。React非常擅长此类操作。通过更改应用程序的状态(即有哪些记录),React将有效地重新渲染。
这是一个非常简单的应用程序。它从开始就有两个项目(foo和bar)应该被呈现。在响应某个操作(在这种情况下为按钮单击)后,更多数据将加载到状态中,因此呈现到页面上。你所需要做的就是修改它,以便代替setTimeout,你可以调用AJAX来获取实际的数据。
在线版本: https://codepen.io/dpwrussell/pen/qadrko
class Application extends React.Component {

  constructor(props) {
    super(props);

    // Start with 2 records
    this.state = {
      records: [
        {
          name: 'foo',
          description: 'Some foo'
        },
        {
          name: 'bar',
          description: 'Some bar'
        }
      ]
    };

    // Bind handlers
    this.loadMoreRecords = this.loadMoreRecords.bind(this);
  }

  // Method to call which gets more records on demand
  // Here I just use setTimeout and some static data, but in your case
  // this would be AJAX to get the data from your server where the callback
  // would do the setState. I use a 2 second delay to exaggerate a delay getting
  // the data from the server.
  loadMoreRecords() {
    setTimeout(() => {
      this.setState({
        records: this.state.records.concat([
          {
            name: 'hello',
            description: 'Some newly loaded hello'
          },
          {
            name: 'world',
            description: 'Some newly loaded world'
          }
        ])
      })
    }, 2000);
  }

  // Method to render whatever records are currently in the state
  renderRecords() {
    const { records } = this.state;
    return records.map(record => {
      return (
        <li>{ `${record.name} - ${record.description}` }</li>
      );
    })
  }

  // React's render method
  render() {
    return (
      <div>
        <h1>List of Records Page</h1>
        <ul>
          { this.renderRecords() }
        </ul>
        <input type='button' onClick={this.loadMoreRecords} value='Load more Records' />
      </div>
    );
  }
}

/*
 * Render the above component into the div#app
 */
ReactDOM.render(<Application />, document.getElementById('app'));

您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - chenatu
是的,我理解你的意思,但那不是React的工作方式。也许如果你提供更多的上下文,并解释为什么客户端渲染Record对你来说行不通,会更好一些。 - dpwr
这里是我的一个案例:React App 中有100多个组件。我不想让它们在第一次渲染时就显示出来,而是在用户通过浏览器拖动页面时通过一些触发事件进行渲染。大多数用户主要关注前几个组件。所以我认为这样可以节省带宽和CPU时间。 - chenatu
这就是React擅长的地方,我已经更新了我的答案。关键在于客户端的React应该始终进行渲染,但你需要从服务器获取需要渲染的内容。在上述情况中,我使用setTimeout来模拟AJAX调用。 - dpwr

-1

使用css-modules-require-hook。它类似于babel-register,但用于.css文件。基本上,它会根据您的钩子配置将require('Record.css')转换为JavaScript对象。因此,您的钩子配置应与您的webpack css-loader配置相同。

将其放置在服务器的入口文件中。

const hook = require('css-modules-require-hook');

hook({/* config */});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接