Я хочу создать приложение Isomorphic react + react-router и через несколько дней googling, теперь я могу получить изоморфное приложение, которое обрабатывает только запрос GET.
Вот что я сделал до сих пор:
- Использование сервера
react-routerдля обработки всего запроса -
react-routerвызовет функцииfetchData, которые находятся в каждом представлении React View, которое соответствует маршруту. - Установите данные, извлеченные ранее, в реквизиты React View и сделайте их в
string - Ввести
stringи данные, полученные до глобальной переменнойwindow.__STATE__, в HTML и доставить HTML-код клиенту - Мы успешно выполнили приложение React с сервера
- Когда клиент завершит загрузку JavaScript-приложения React App, он попытается выполнить рендеринг. Но мы передаем состояние из
window.__STATE__в качестве опоры нашего приложения React, а React не будет повторно отображаться, потому что состояние такое же
Проблема заключается в том, что он не будет работать с запросом POST/PUT/DELETE/WHATEVER. При обработке запроса GET react-router есть информация о params и query. Например, если у нас есть маршрут: /user/:uid и запрос клиента этот URL: /user/1?foo=bar, тогда params будет: {uid: 1} и query будет {foo: 'bar'}
react-router затем может передать его функции fetchData, чтобы он знал, чтобы получить пользователя с uid из 1 и делать что-либо с запросом foo.
В запросе POST react-router не знает о параметрах POST. На сервере, конечно, мы могли бы передать параметры POST функции fetchData, но как насчет клиента? Он не знает, что такое параметры POST.
Есть ли способ, который сервер мог бы сообщить Клиенту о параметрах POST? Ниже приведен пример моего входа в систему. Я хочу, когда пользователь отправит форму, сервер выдаст сообщение об ошибке при ошибке или перенаправит ее на панель управления при успешном завершении.
fetchData.js
import whenKeys from 'when/keys';
export default (authToken, routerState) => {
var promises = routerState.routes.filter((match) => {
return match.handler.fetchData;
}).reduce((promises, match) => {
promises[match.name] = match.handler.fetchData(authToken, routerState.params, routerState.query);
return promises;
}, {});
return whenKeys.all(promises);
}
server.js
...
app.use((req, res) => {
const router = Router.create({
routes,
location: req.originalUrl,
onError: next,
onAbort: (abortReason) => {
next(abortReason);
}
});
router.run((Handler, state) => {
fetchData(authToken, state).then((data) => {
// render matched react View and generate the HTML
// ...
})
});
});
...
login.jsx
import React from 'react';
import DocumentTitle from 'react-document-title';
import api from './api';
export default class Login extends React.Component {
constructor(props) {
super(props);
// how to fill this state with POST parameters on error?
// how to redirect on success?
// and remember that this file will be called both from server and client
this.state = {
error: '',
username: '',
password: ''
};
}
// I saw some people use this function, but it'll only work if
// the form method is GET
static willTransitionTo(transition, params, query) {
// if only we could read POST parameters here
// we could do something like this
transition.wait(
api.post('/doLogin', postParams).then((data) => {
transition.redirect(`/dashboard`);
});
);
}
render() {
return (
<DocumentTitle title="Login">
<div className="alert alert-danger">{this.state.error}</div>
<form method="post">
<input type="text" name="username" value={this.state.username} onChange={this._onFieldChange('username')} placeholder="Username" /><br />
<input type="password" name="password" value={this.state.password} onChange={this._onFieldChange('password')} placeholder="Password" /><br />
<button type="submit">Login</button>
</form>
</DocumentTitle>
);
}
_onFieldChange(name) {
var self = this;
return (e) => {
e.preventDefault();
var nextState = {};
nextState[name] = e.target.value;
self.setState(nextState);
}
}
}

