[英]How to Handle Post Request in Isomorphic React + React Router Application
I want to build Isomorphic react
+ react-router
application and after a few days googling, now I can achieve isomorphic application that only handles GET request. 我想建立Isomorphic react
+ react-router
应用程序,经过几天的谷歌搜索,现在我可以实现只处理GET请求的同构应用程序。
Here's what I've done so far: 这是我到目前为止所做的:
react-router
to handle all request 服务器使用react-router
来处理所有请求 react-router
will call fetchData
functions that resides in each React View that matches the route. react-router
将调用驻留在与路由匹配的每个React View中的fetchData
函数。 string
将之前获取的数据设置为React View的props并将其呈现为string
string
and data fetched before as global variable window.__STATE__
into HTML and deliver the HTML to the client 将之前获取的string
和数据作为全局变量window.__STATE__
注入HTML并将HTML传递给客户端 window.__STATE__
as the props of our React App, and React will not re-render because the state is the same 但是我们从window.__STATE__
传递状态作为我们的React App的道具,并且React不会重新渲染,因为状态是相同的 The problem is it will not work with POST/PUT/DELETE/WHATEVER request. 问题是它不适用于POST / PUT / DELETE / WHATEVER请求。 When handling GET request, react-router
have information about params
and query
. 处理GET请求时, react-router
有关于params
和query
。 For example if we have a route: /user/:uid
and client request this url: /user/1?foo=bar
, then params
would be: {uid: 1}
and query
would be {foo: 'bar'}
例如,如果我们有一个路由: /user/:uid
和客户端请求这个url: /user/1?foo=bar
,那么params
将是: {uid: 1}
并且query
将是{foo: 'bar'}
react-router
then can pass it down to fetchData
function so it will know to fetch user with uid
of 1 and do whatever with foo
query. react-router
然后可以将它传递给fetchData
函数,这样它就会知道用uid
为1获取用户并用foo
查询做任何事情。
While in POST request, react-router
doesn't know about the POST parameters. 在POST请求中, react-router
不知道POST参数。 On Server, of course we could pass the POST parameters to fetchData
function, but what about the Client? 在服务器上,我们当然可以将POST参数传递给fetchData
函数,但客户端呢? It doesn't know what the POST parameters are. 它不知道POST参数是什么。
Is there a way that the server could tell the Client about the POST parameters? 有没有办法让服务器告诉客户有关POST参数的信息? Below is an example of my Login View. 以下是我的登录视图的示例。 I want when user submit the form, the server will render error message on error, or redirect it to dashboard on success. 我希望当用户提交表单时,服务器将在出错时呈现错误消息,或者在成功时将其重定向到仪表板。
fetchData.js 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 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 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);
}
}
}
On the client side, you get POST data by extracting values from your form inputs in a way which corresponds to what you would have received on the server had the form been submitted normally. 在客户端,您可以通过从表单输入中提取值来获得POST数据,其方式与您在正常提交表单时在服务器上收到的内容相对应。
So now you have your POST data, but you still have the problem that there's no way to feed the POST data into your transition hooks in React Router 0.13.x and earlier. 所以现在你有了POST数据,但是仍然存在无法将POST数据提供给React Router 0.13.x及更早版本的转换挂钩的问题。 I created a pull request for this feature which has now been closed because it was included as part of the rewrite for the upcoming v1.0 release. 我为此功能创建了一个pull请求,该请求现已关闭,因为它是作为即将发布的v1.0版本重写的一部分而包含的。
The gist of it is that locations now have a state object for squireling away any extra data you need about the current request/transition (the two are analagous) being handled: 它的要点是,位置现在有一个状态对象,用于搜集关于当前请求/转换所需的任何额外数据(两个是类似的)正在处理:
req.body
在服务器上,您一次处理一个请求,因此您使用req.body
数据创建一个静态Location transitionTo()
. 在客户端上,您将状态对象(包含提取的表单数据)传递给transitionTo()
。 Now your transition hook is capable of receiving the same form data in both environments. 现在,您的转换挂钩能够在两个环境中接收相同的表单数据。 If things go well, great! 如果事情进展顺利,太好了! If things don't go well, you need a way to pass errors and re-render the form again. 如果事情进展不顺利,您需要一种方法来传递错误并重新渲染表单。 New state object to the rescue again! 新州反对再次救援! Use transition.redirect()
and pass both input data and errors and you now have everything you need to render on both sides. 使用transition.redirect()
并传递输入数据和错误,您现在拥有了双方都需要渲染的所有内容。
I'm not going into more specific detail right now because v1.0 is still in beta and v0.13.x doesn't have the necessary API to do this anyway, but I have a repository which uses the pull request above to implement this workflow with 0.13.x which you could look at in the meantime: 我现在还没有详细介绍,因为v1.0仍处于测试阶段,v0.13.x无论如何都没有必要的API,但是我有一个使用上面的pull请求实现的存储库0.13.x的这个工作流程,您可以在此期间查看:
Here are some rough flow diagrams of the process, too: 以下是该过程的一些粗略流程图:
I've also created a few reusable modules related to this scenario: 我还创建了一些与此场景相关的可重用模块:
<AutoForm>
, which you can use instead of <form>
to receive all the data from a form's inputs as an argument to its onSubmit
handler react-auto-form提供<AutoForm>
,您可以使用它来代替<form>
从表单的输入接收所有数据作为其onSubmit
处理程序的参数 <form>
what React Router's <Link>
is to <a>
- it handles triggering a transition to the given action
, passing method
and body
(form data) state - this will be updated for v1.0 soon. react-router-form ,它是<form>
React Router的<Link>
是什么<a>
- 它处理触发到给定action
的转换,传递method
和body
(表单数据)状态 - 这将更新为v1 .0很快。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.