简体   繁体   English

如何处理同构React + React路由器应用中的后置请求

[英]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: 这是我到目前为止所做的:

  1. Server use react-router to handle all request 服务器使用react-router来处理所有请求
  2. react-router will call fetchData functions that resides in each React View that matches the route. react-router将调用驻留在与路由匹配的每个React View中的fetchData函数。
  3. Set the data fetched before into props of the React View and render it into string 将之前获取的数据设置为React View的props并将其呈现为string
  4. Inject the string and data fetched before as global variable window.__STATE__ into HTML and deliver the HTML to the client 将之前获取的string和数据作为全局变量window.__STATE__注入HTML并将HTML传递给客户端
  5. We have successfully render React App from the server 我们已成功从服务器呈现React App
  6. When the client finished loading our React App javascript, it will try to render. 当客户端完成加载我们的React App javascript后,它将尝试渲染。 But we pass the state from 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有关于paramsquery 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);
    }
  }
}

Getting "POST" data on the client 在客户端上获取“POST”数据

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数据,其方式与您在正常提交表单时在服务器上收到的内容相对应。

Using POST data 使用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: 它的要点是,位置现在有一个状态对象,用于搜集关于当前请求/转换所需的任何额外数据(两个是类似的)正在处理:

  • On the server, you're dealing with one request at a time, so you create a static Location with data from req.body 在服务器上,您一次处理一个请求,因此您使用req.body数据创建一个静态Location
  • On the client you pass the state object (containing extracted form data) to 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的这个工作流程,您可以在此期间查看:

  • isomorphic-lab - the README gives an overview of how things fit together. 同构实验室 - 自述文件概述了事物如何组合在一起。

Here are some rough flow diagrams of the process, too: 以下是该过程的一些粗略流程图:

Server POST with errors and redisplay 服务器POST有错误并重新显示

服务器流程图

Client POST with errors and redisplay 客户端POST有错误并重新显示

客户端流程图


I've also created a few reusable modules related to this scenario: 我还创建了一些与此场景相关的可重用模块:

  • get-form-data gets data from a form's inputs in the format it would have been POSTed in. get-form-data以表单输入的格式从表单的输入中获取数据。
  • react-auto-form provides <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处理程序的参数
  • react-router-form , which is to <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的转换,传递methodbody (表单数据)状态 - 这将更新为v1 .0很快。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM