我注意到reactDOM.renderToString()在服务器上渲染大型组件树时,该方法开始显着减慢.
一点背景.该系统是一个完全同构的堆栈.最高级别的App组件呈现模板,页面,dom元素和更多组件.查看反应代码,我发现它渲染了~1500个组件(这包括任何简单的dom标记,它被视为一个简单的组件,<p>this is a react component</p>.
在开发中,渲染~1500个组件需要大约200-300ms.通过删除一些组件,我能够在~175-225ms内获得~1200个组件.
在生产中,〜1500个组件上的renderToString大约需要50-200ms.
时间似乎是线性的.没有一个组件是慢的,而是它的总和.
这会在服务器上产生一些问题.冗长的方法导致服务器响应时间过长.TTFB比它应该高很多.使用api调用和业务逻辑,响应应该是250ms,但是使用250ms renderToString它会加倍!SEO和用户不好.此外,作为同步方法,renderToString()可以阻止节点服务器并备份后续请求(这可以通过使用2个单独的节点服务器来解决:1作为Web服务器,1作为服务来单独呈现反应).
理想情况下,生产中需要5-50ms的renderToString.我一直在研究一些想法,但我不确定最好的方法是什么.
任何标记为"静态"的组件都可以缓存.通过使用呈现的标记保持缓存,renderToString()可以在呈现之前检查缓存.如果找到一个组件,它会自动抓取该字符串.在高级组件中执行此操作将保存所有嵌套子组件的安装.您必须使用当前的rootID替换缓存的组件标记的反应rootID.
通过将组件定义为"简单",react应该能够在呈现时跳过所有生命周期方法.反应已经这样做了芯反应,DOM组件(<p/>,<h1/>,等).很高兴扩展自定义组件以使用相同的优化.
服务器上不需要返回的组件(没有SEO值)可以简单地跳过.客户端加载后,设置一个clientLoaded标志true并将其传递给强制重新渲染.
到目前为止,我实现的唯一解决方案是减少服务器上呈现的组件数量.
我们正在研究的一些项目包括:
有人遇到过类似的问题吗?你有什么能做的?谢谢.
performance render-to-string reactjs isomorphic-javascript react-dom
使用同构应用程序设置应用程序的初始状态的一般做法是什么?没有Flux我会简单地使用类似的东西:
var props = { }; // initial state
var html = React.renderToString(MyComponent(props);
Run Code Online (Sandbox Code Playgroud)
然后通过快速把手渲染该标记并显示通过{{{reactMarkup}}.
在客户端设置初始状态我会做这样的事情:
if (typeof window !== 'undefined') {
var props = JSON.parse(document.getElementById('props').innerHTML);
React.render(MyComponent(props), document.getElementById('reactMarkup'));
}
Run Code Online (Sandbox Code Playgroud)
所以基本上你是在服务器和客户端上设置状态两次,但是React会比较这些差异,在大多数情况下,它不会通过重新渲染来影响性能.
当您在Flux架构中拥有操作和存储时,此原则将如何工作?在我的组件里面我可以做到:
getInitialState: function() {
return AppStore.getAppState();
}
Run Code Online (Sandbox Code Playgroud)
但是现在我如何从服务器设置AppStore中的初始状态?如果我使用React.renderToString没有传递的属性,它将调用AppStore.getAppState()哪个不会有任何内容,因为我仍然不明白我将如何在服务器上的商店中设置状态?
我仍在寻找一种干净的解决方案,不涉及使用Fluxible,Fluxxor,Reflux等第三方Flux实施.
使用Redux.
我正在尝试使用isomorphic Node.js,Express,Webpack,React app工作.我收到以下错误.有关如何解决它的任何建议?
Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:
(client) rgin:0;display:flex;-webkit-align-items:
(server) rgin:0;display:flex;align-items:center;j
warning @ …Run Code Online (Sandbox Code Playgroud) 我认为我在概念上缺少使用React.js进行服务器端渲染的东西
假设我想创建一个页面来显示来自服务器端数据库的项目,并使用输入字段来过滤它们.
我想要一个页面:
/items?name=foobar假设我有一个公共REST API来查询客户端的项目.
从概念上讲,我在第一次请求(GET /items?name=foobar)时想要做的是:
initialName)所以我尝试了这个:
// A stateful component, maintaining the value of a query field
var ItemForm = React.createClass({
getInitialState : function () {
return {
name : this.props.initialName
};
},
handleInputValueChanged : function() {
var enteredName = this.refs.query.getDOMNode().value.trim();
this.props.onNameChanged(enteredName);
},
render : function () {
return React.DOM.form({
children : [
React.DOM.label({
children : "System name"
}),
React.DOM.input({
ref : "query",
value : this.state.name,
onChange : this.handleInputValueChanged …Run Code Online (Sandbox Code Playgroud) 我正在为同构javascript应用程序进行POC以从服务器端呈现html.POC正在使用简单的html,但我想进行api调用并获取json响应并发送到render函数.我试过各种各样的方法,但它没有用.你们其中一个请告诉我我失踪的地方.
我很反应js,任何帮助都会非常感激
loadCategoriesFromServer: function() {
var self = this;
// get walking directions from central park to the empire state building
var http = require("http");
url = "api url here";
var request = http.get(url, function (response) {
// data is streamed in chunks from the server
// so we have to handle the "data" event
var buffer = "",
data,
route;
response.on("data", function (chunk) {
buffer += chunk;
});
response.on("end", function (err) {
data = JSON.parse(buffer);
//console.log(data.d);
//console.log(data.d.Items);
self.setState({
categories: …Run Code Online (Sandbox Code Playgroud) 我使用React和Express遇到了同构JavaScript应用程序的问题.
我正在尝试使用axios.get在我的组件安装时发出HTTP请求
componentDidMount() {
const url = 'http://ufc-data-api.ufc.com/api/v3/iphone/fighters/title_holders';
axios.get(url).then( res => {
//use res to update current state
})
}
Run Code Online (Sandbox Code Playgroud)
我从API获得状态200 res,但我没有得到任何响应数据并在我的控制台中收到错误
XMLHttpRequest cannot load http://ufc-data-api.ufc.com/api/v3/iphone/fighters/title_holders.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:3000' is therefore not allowed access.
Run Code Online (Sandbox Code Playgroud)
但是,如果我在server.js中发出请求
const url = 'http://ufc-data-api.ufc.com/api/v3/iphone/fighters/title_holders';
axios.get(url).then(res => {
//console.log(res);
});
Run Code Online (Sandbox Code Playgroud)
它工作正常,我在服务器启动时获得响应数据.这是实际API的问题还是我做错了什么?如果这是一个CORS问题,我猜测server.js中的请求也不起作用?谢谢!
在同构呈现的页面图像可以在主script.js文件之前下载.因此,可以在react注册onLoad事件之前加载图像- 从不触发此事件.
script.js
constructor(props) {
super(props);
this.handleImageLoaded = this.handleImageLoaded.bind(this);
}
handleImageLoaded() {
console.log('image loaded');
}
render() {
return (
<img src='image.jpg' onLoad={this.handleImageLoaded} />
);
}
Run Code Online (Sandbox Code Playgroud)
image.jpg大于script.js在这种情况下一切正常.在最终加载图像之前注册事件,因此在控制台中是image loaded消息.
image.jpg小于script.js在这种情况下,您可以看到帖子开头描述的问题.onLoad事件未触发.
为了onLoad在方案2中触发事件,我该怎么办?
要检测渲染时图像是否准备好,您应该检查complete纯javascript img对象上的属性:
constructor(props) {
super(props);
this.state = { loaded: false };
this.handleImageLoaded = this.handleImageLoaded.bind(this);
this.image = React.createRef();
}
componentDidMount() {
const img …Run Code Online (Sandbox Code Playgroud) 我正在建立一个CMS系统来管理营销登陆页面.在"编辑登录页面"视图中,我希望能够为用户正在编辑的任何登录页面加载相关的样式表.我怎么能用React做这样的事情?
我的应用程序是完全React,同构,在Koa上运行.我的相关页面的基本组件层次结构看起来像这样:
App.jsx (has `<head>` tag)
??? Layout.jsx (dictates page structure, sidebars, etc.)
??? EditLandingPage.jsx (shows the landing page in edit mode)
Run Code Online (Sandbox Code Playgroud)
着陆页的数据(包括要加载的样式表的路径)是异步提取EditLandingPage的ComponentDidMount.
如果您需要任何其他信息,请与我们联系.很想得到这个想法!
额外奖励:我还想在离开页面时卸载样式表,我认为我可以反过来回答任何问题ComponentWillUnmount,对吧?
我有关于redux和同构应用的3个一般问题:
提前致谢.
我正在用webpack编写一个同构的Key Value Store.
这是我目前加载库的方法,这显然不起作用,因为webpack想解决这两个问题require.什么是正确的方法?
var db = null;
if (typeof window === 'undefined') {
// node context
db = require('level');
} else {
// browser context
db = require('gazel');
}
Run Code Online (Sandbox Code Playgroud)
我知道,你可以为webpack 提供一个目标.但我不知道如何使用它.
谢谢!
reactjs ×9
javascript ×7
node.js ×3
express ×2
webpack ×2
axios ×1
flux ×1
leveldb ×1
performance ×1
react-dom ×1
redux ×1
stylesheet ×1