具有客户端和服务器端渲染的 React 同构组件
React isomorphic component with both client-side and server-side rendering
我想创建一个同时具有客户端和服务器端渲染的 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.renderToString
和react-router
搜索了一些服务器端渲染的例子。但是,没有关于客户端和服务器端渲染的教程。
我想要实现的是,客户端首先加载并渲染组件<Main />
,然后从服务器端加载<Record />
。
另一个问题是,如何使用 renderToString 加载样式模块 Record.css,因为我认为在这个 renderToString 中只能加载 html 而不是 css。
使用css-modules-require-hook。它类似于 babel-register 但用于 .css 文件。基本上,它根据您的钩子配置将您的 require('Record.css') 转换为 javascript 对象。所以你的钩子配置应该和你的 webpack css-loader 配置一样。
放在你服务器的入口文件中。
const hook = require('css-modules-require-hook');
hook({/* config */});
当人们提到服务器端呈现时,他们通常指的是顶层应用程序在特定路径上的初始呈现,而不是单个组件。
我无法理解您的用例是针对您的请求。您的 React 应用程序是 Fragments
的一棵大树,因此在服务器端渲染单个组件并没有多大意义。如果你想让 Record
成为 React 的一部分,那么客户端需要知道它,那么为什么不像往常一样在客户端渲染它呢?
如果您真的需要在服务器端呈现它,那么我想您可以构建 Record 组件,以便它执行 AJAX 请求,然后可以使用 [=15] 呈现返回的 html =],但我不推荐它。
我的猜测是 Record
需要来自服务器端的某种数据,这就是为什么要在那里呈现它?相反,只需将该数据作为 JSON 获取并使用它来呈现组件客户端。
看了你的评论,我知道你想做什么了。您想要的是响应某些事件(向下滚动、单击按钮或其他)从服务器动态加载内容(未呈现 html)。 React 非常擅长这一点。通过更改应用程序的状态(即有哪些记录),React 将有效地处理重新渲染。
这是一个非常简单的应用程序。它从应该呈现的 2 个项目(foo 和 bar)开始。为了响应一个动作(在本例中是单击按钮),更多的数据被加载到状态中,从而呈现给页面。您需要做的就是修改它,以便您对后端执行 AJAX 调用以获取实际数据,而不是 setTimeout
。
在线版本: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'));
我想创建一个同时具有客户端和服务器端渲染的 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.renderToString
和react-router
搜索了一些服务器端渲染的例子。但是,没有关于客户端和服务器端渲染的教程。
我想要实现的是,客户端首先加载并渲染组件<Main />
,然后从服务器端加载<Record />
。
另一个问题是,如何使用 renderToString 加载样式模块 Record.css,因为我认为在这个 renderToString 中只能加载 html 而不是 css。
使用css-modules-require-hook。它类似于 babel-register 但用于 .css 文件。基本上,它根据您的钩子配置将您的 require('Record.css') 转换为 javascript 对象。所以你的钩子配置应该和你的 webpack css-loader 配置一样。
放在你服务器的入口文件中。
const hook = require('css-modules-require-hook');
hook({/* config */});
当人们提到服务器端呈现时,他们通常指的是顶层应用程序在特定路径上的初始呈现,而不是单个组件。
我无法理解您的用例是针对您的请求。您的 React 应用程序是 Fragments
的一棵大树,因此在服务器端渲染单个组件并没有多大意义。如果你想让 Record
成为 React 的一部分,那么客户端需要知道它,那么为什么不像往常一样在客户端渲染它呢?
如果您真的需要在服务器端呈现它,那么我想您可以构建 Record 组件,以便它执行 AJAX 请求,然后可以使用 [=15] 呈现返回的 html =],但我不推荐它。
我的猜测是 Record
需要来自服务器端的某种数据,这就是为什么要在那里呈现它?相反,只需将该数据作为 JSON 获取并使用它来呈现组件客户端。
看了你的评论,我知道你想做什么了。您想要的是响应某些事件(向下滚动、单击按钮或其他)从服务器动态加载内容(未呈现 html)。 React 非常擅长这一点。通过更改应用程序的状态(即有哪些记录),React 将有效地处理重新渲染。
这是一个非常简单的应用程序。它从应该呈现的 2 个项目(foo 和 bar)开始。为了响应一个动作(在本例中是单击按钮),更多的数据被加载到状态中,从而呈现给页面。您需要做的就是修改它,以便您对后端执行 AJAX 调用以获取实际数据,而不是 setTimeout
。
在线版本: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'));