Как обработать почтовый запрос в изоморфном приложении React + React Router
Я хочу построить Изоморфныйreact
+ react-router
приложение и после нескольких дней поиска в Google, теперь я могу добиться изоморфного приложения, которое обрабатывает только запрос GET.
Вот что я сделал до сих пор:
Использование сервераreact-router
обрабатывать все запросыreact-router
позвонюfetchData
функции, которые находятся в каждом React View, который соответствует маршруту.Установите данные, выбранные ранее, в подпорки React View и отобразите их вstring
Введитеstring
и данные извлекаются как глобальная переменнаяwindow.__STATE__
в HTML и доставить HTML клиентуМы успешно представили приложение React с сервера.Когда клиент закончит загрузку нашего JavaScript-приложения React, он попытается выполнить рендеринг. Но мы передаем состояние от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. На сервере, конечно, мы могли бы передать параметры POSTfetchData
функция, а как насчет клиента? Он не знает, что такое параметры 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's 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);
}
}
}