Я думаю, что я концептуально отсутствует что-то с рендерингом на стороне сервера, используя React.js
Предположим, что я хочу создать страницу для отображения элементов из серверной базы данных с полем ввода для их фильтрации.
Мне нужна страница:
Предположим, что у меня есть открытый REST API для запроса элементов на стороне клиента.
Концептуально, что я хочу сделать при первом запросе (GET/items? name = foobar):
Итак, я пробовал это:
// A statefull 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
})
]
});
}
});
Как я понимаю, мне нужен простой компонент для отображения списка, получив его как "prop":
// 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 statefull 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' propery 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 на стороне клиента, что мне делать? Я знаю, где я хочу, чтобы мой дом был визуализирован, но какой исходный реквизит следует передать компоненту реакции?
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 "удаляется" на стороне клиента, с этим сообщением:
Реакция попыталась использовать разметку повторного использования в контейнере, но контрольная сумма недействительно. Обычно это означает, что вы используете рендеринг сервера и разметка, сгенерированная на сервере, была не тем, что клиент ожидая. Реагируйте новую инъекцию, чтобы компенсировать, какие работы, но вы потеряли многие преимущества рендеринга сервера. Вместо этого, цифра почему создается разметка на клиенте, сервер.
Обратите внимание, что только разметка моего компонента ItemList удаляется, поэтому я предполагаю, что это проблема с реализацией моего компонента, но я не знаю, с чего начать.
Я на правильном пути? Или я что-то пропущу?
Спасибо
При использовании рендеринга сервера вы всегда должны передавать те же реквизиты, которые использовались для рендеринга компонента на сервере. В этом случае вам нужно передать ту же самую начальную идентификационную строку, чтобы React.renderComponent
подобрал разметку, обработанную сервером (просто JSONifying реквизита и поместив ее в вызов renderComponent
).
Ваша общая структура чтения из initialItems, когда это указано, имеет смысл для меня. Это позволяет вам либо составлять компонент с предварительно загруженными данными, либо тот, у которого его нет. То, что вам нужно, чтобы установить начальное состояние, зависит от того, что вы хотите показать в тех случаях, когда вы создаете совершенно новый компонент с нуля. (Если вы всегда набираете разметку, обработанную сервером, вы можете просто всегда передавать реквизиты initialName
и initialItems
.)
Надеюсь, что это имеет смысл.