[英]Facebook React.js: how do you render stateful components on the server?
我認為我在概念上缺少使用React.js進行服務器端渲染的東西
假設我想創建一個頁面來顯示來自服務器端數據庫的項目,並使用輸入字段來過濾它們。
我想要一個頁面:
/items?name=foobar
這樣的URL 假設我有一個公共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
})
]
});
}
});
據我了解,我需要一個簡單的組件來顯示列表,將其作為“道具”接收:
// A stateless component, displaying a list of item
var ItemList = return React.createClass({
propTypes : {
items : React.PropTypes.array
},
render : function () {
return React.DOM.ul({
children : _.map(this.props.items, function (item) {
return React.DOM.li({
children : [
React.DOM.span({
children : ["Name : ", item.name].join(" ")
})]
});
})
});
}
});
我試過這個:
// A stateful react component, maintaining the list of items
var ItemPage = React.createClass({
getInitialState : function () {
// ?????
// This is where I'm sure the problem lies.
// How can this be known both on server and client side ?
return {
items : this.props.initialItems || []
};
},
queryItems : function (enteredName) {
var self = this;
// The field was emptied, we must clear everything
if (!enteredName) {
this.setState({
items : []
});
} else {
// The field was changed, we want to do a query
// then change the state to trigger a UI update.
// The query code is irrelevant, I think.
doQuery(enteredName).then(function (items) {
self.setState({
items : items
});
});
}
},
render : function () {
// I don't want to display the same view
// if there is no results.
// This uses a 'state' property of the page
var results = null;
if (_.isEmpty(this.state.items)) {
results = React.DOM.div({
ref : "results",
children : "No results"
});
} else {
results = ItemListView({
// Here items is a 'prop', the ItemList is technically
// stateless
items : this.state.items
});
}
return React.DOM.div({
children : [
ItemForm({
initialName : this.props.initialName,
onNameChanged : this.queryItems
}),
results
]
});
}
});
那就是我被困住的地方。 我可以使用以下內容在服務器端渲染內容:
var name = // The name from the query parameters
var items = doQueryOnServerSide(name);
React.renderComponentAsString(ItemPage({
initialName : name,
initialItems : items
});
但是當我嘗試編寫客戶端javascript時,我該怎么辦? 我知道我想要在哪里渲染我的dom,但是我應該將哪些初始道具傳遞給反應組件?
React.renderComponent(ItemPage({
initialName : ??? // Read the name parameter from URL ?
initialItems : ??? // I don't know yet, and I don't want to make an API call until the user entered something in the input box
});
我嘗試過的大多數嘗試最終都會在客戶端“刪除”DOM,並顯示以下消息:
React嘗試在容器中使用重用標記,但校驗和無效。 這通常意味着您正在使用服務器呈現,並且在服務器上生成的標記不是客戶端所期望的。 React注入了新的標記以補償哪些有效但你已經失去了服務器渲染的許多好處。 相反,弄清楚為什么生成的標記在客戶端或服務器上是不同的。
請注意,只有我的ItemList組件的標記被刪除,所以我認為這是我的組件的實現問題,但我真的不知道從哪里開始。
我是在正確的軌道上嗎? 或者我完全錯過了什么?
使用服務器渲染時,應始終傳遞用於在服務器上呈現組件的相同道具。 在這種情況下,您需要傳遞相同的initialItems prop,以便React.renderComponent
獲取服務器呈現的標記(通過簡單地JSONifying道具並將其放入對renderComponent
的調用中)。
從指定的initialItems讀取的一般結構對我來說是有意義的。 這樣做允許您創建具有預加載數據的組件或不具有預加載數據的組件。 您需要將初始狀態設置為取決於您要從頭開始渲染全新組件時要顯示的內容。 (如果你總是拿起服務器渲染的標記,那么你可以簡單地傳遞initialName
和initialItems
道具。)
希望有道理。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.