Выборка данных перед рендерингом на стороне сервера
Прямо сейчас я открываю Este.js и у меня есть небольшая проблема с изоморфными приложениями. Я не понимаю, как сделать вызов API перед рендерингом на стороне сервера с помощью renderToString().
Одно из решений заключается в выполнении всех выборок данных на уровне маршрутизатора с использованием React Router. В зависимости от маршрута верхнего уровня, я могу предсказать, какие данные понадобятся, сделать вызов API и затем вызвать React.renderToString.
Отлично, но я все еще должен объявить зависимости данных на уровне компонентов И на уровне маршрутизатора. В итоге я пишу один и тот же код дважды, и я не верю, что это лучший способ сделать это.
РЕДАКТИРОВАТЬ: Хорошо, сейчас я могу сделать что-то, что я хочу. Используя React-Router и эту ссылку, я смог сделать следующее:
Давая это глобальное состояние приложения, я хочу предварительно выбирать todos при указании / todos
initialstate.js
{
auth: {
data: null,
form: null
},
examples: {
editable: {
state: null,
text: 'Some inline-editable text.'
}
},
i18n: {
formats: {},
locales: initialLocale,
messages: messages[initialLocale]
},
pendingActions: {},
todos: {
editables: {},
newTodo: {
title: ''
},
list: [{
id: 1,
title: 'first todo yipiyo'
}]
},
users: {
viewer: null
}
}
todos.react.js
В компоненте todo я объявляю статическую функцию fetchData. Поскольку я хочу получить правильный ключ в моем appState, я передаю "список" в качестве параметра. Чувствует себя грязным
class Todos extends Component {
static fetchData(){
return actions.loadAllTodos('list');
}
componentDidMount(){
Todos.fetchData();
}
render() {
...
}
}
actions.js
Вызов API и прочее, я передаю ключ к обещанию - чувствует себя счастливым
export function loadAllTodos(key) {
const promise = new Promise((resolve, reject) => {
Api.get()
.then(res => {
res.key = key; //hacky time
resolve(res)
})
.catch(err => {
reject(err);
})
});
return dispatch(loadAllTodos, promise);
}
render.js
router.run((Handler, routerState) => {
var promise = Promise.all(routerState.routes
.filter(route => route.handler.fetchData)
.map(route => {
return route.handler.fetchData();
})
);
promise.then(resp => {
console.log(resp);
//Displays :
[ { id: 2, title: 'Im a second todo' },{ id: 3, title: 'I like todo' },
cursor: 'list' ]
//Some stuff to add resp to appState, using the correct key, yey iso+api=win
appState = mergeThisWithMagic(appState, resp);
const html = preloadAppStateThenRenderHtml(Handler, appState);
const notFound = routerState.routes.some(route => route.name ===
'not-found');
const status = notFound ? 404 : 200;
res.status(status).send(html);
resolve();
});
});
Как видите, я создам функцию для обновления appState с обновленным списком todoList.
Это нормально делать все это? Я хотел бы получить некоторую обратную связь, пожалуйста, потому что я чувствую, что иду по темному пути:(.
1 ответ
Я выполнил это в своем изоморфном серверном приложении, поместив свои функции fetchData в statics
объект компонента (ов) и использование обещаний, которые ждут, пока все данные не будут возвращены, прежде чем отобразить приложение в строку.
Затем вы передадите возвращенные данные в обработанный компонент через реквизит. Этот пример сыграл важную роль в моей разработке этого приложения. React Router Мега Демо.