Javascript 如何在同构React+;反应路由器应用

Javascript 如何在同构React+;反应路由器应用,javascript,reactjs,react-router,Javascript,Reactjs,React Router,我想构建同构的react+react路由器应用程序,在谷歌搜索几天后,现在我可以实现只处理GET请求的同构应用程序 以下是我迄今为止所做的工作: 服务器使用react路由器处理所有请求 react路由器将调用驻留在与路由匹配的每个react视图中的fetchData函数 将之前获取的数据设置为React视图的道具,并将其呈现为string 将字符串和之前获取的数据作为全局变量窗口注入HTML,并将HTML传递给客户端 我们已成功从服务器渲染React应用程序 当客户端加载完我们的React应用程

我想构建同构的
react
+
react路由器
应用程序,在谷歌搜索几天后,现在我可以实现只处理GET请求的同构应用程序

以下是我迄今为止所做的工作:

  • 服务器使用
    react路由器
    处理所有请求
  • react路由器
    将调用驻留在与路由匹配的每个react视图中的
    fetchData
    函数
  • 将之前获取的数据设置为React视图的道具,并将其呈现为
    string
  • 字符串
    和之前获取的数据作为全局变量
    窗口注入HTML,并将HTML传递给客户端
  • 我们已成功从服务器渲染React应用程序
  • 当客户端加载完我们的React应用程序javascript后,它将尝试渲染。但是我们将状态从
    窗口传递。作为React应用程序的道具,React不会重新渲染,因为状态相同
  • 问题是它不能处理POST/PUT/DELETE/WHATEVER请求。处理GET请求时,
    react router
    具有有关
    params
    query
    的信息。例如,如果我们有一个路由:
    /user/:uid
    ,客户端请求这个url:
    /user/1?foo=bar
    ,那么
    参数将是:
    {uid:1}
    查询将是
    {foo:'bar}

    react路由器
    然后可以将其传递给
    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'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);
        }
      }
    }
    
    从“React”导入React;
    从“react document title”导入DocumentTitle;
    从“/api”导入api;
    导出默认类登录扩展React.Component{
    建造师(道具){
    超级(道具);
    //如何在出错时用POST参数填充此状态?
    //成功后如何重定向?
    //请记住,此文件将同时从服务器和客户端调用
    此.state={
    错误:“”,
    用户名:“”,
    密码:“”
    };
    }
    //我看到一些人使用这个功能,但只有在
    //表单的方法是GET
    静态WillTransition(转换、参数、查询){
    //如果我们能在这里读取POST参数就好了
    //我们可以这样做
    过渡,等等(
    api.post('/doLogin',postParams)。然后((数据)=>{
    重定向(`/dashboard`);
    });
    );
    }
    render(){
    返回(
    {this.state.error}
    

    登录 ); } _onFieldChange(名称){ var self=这个; 返回(e)=>{ e、 预防默认值(); var nextState={}; nextState[name]=e.target.value; 自设置状态(nextState); } } }
    获取客户机上的“POST”数据 在客户端,您可以通过从表单输入中提取值来获取POST数据,该值与正常提交表单时在服务器上收到的值相对应

    使用POST数据 现在您有了POST数据,但仍然存在一个问题,即无法将POST数据提供给React Router 0.13.x及更早版本中的转换挂钩。我创建了一个已关闭的,因为它是即将发布的v1.0版本重写的一部分

    其要点是,位置现在有一个state对象,用于喷射出您需要的关于当前处理的请求/转换(这两个都是analagous)的任何额外数据:

    • 在服务器上,您一次处理一个请求,因此您使用
      req.body
    • 在客户端上,将状态对象(包含提取的表单数据)传递给
      transitiono()
    现在,您的转换挂钩能够在两种环境中接收相同的表单数据。如果一切顺利,那太好了!如果事情进展不顺利,您需要一种方法来传递错误并重新呈现表单。新政府再次反对营救!使用
    transition.redirect()
    并传递输入数据和错误,您现在拥有了需要在两侧渲染的所有内容

    我现在不打算讨论更具体的细节,因为v1.0仍处于beta版本,而v0.13.x无论如何都没有必要的API来实现这一点,但我有一个存储库,它使用上面的pull请求来使用0.13.x实现此工作流,您可以同时查看:

    • -自述文件概述了事物如何组合在一起
    以下是该过程的一些粗略流程图:

    服务器发布错误并重新显示

    客户端发布错误并重新显示


    我还创建了一些与此场景相关的可重用模块:

    • 从表单的输入中获取数据,数据的格式应为该表单发布时使用的格式
    • 提供
      ,即
      路由器的
      的反应-它处理触发到给定
      操作的转换,传递
      方法
      主体
      (表单数据)状态-这将很快更新到v1.0

    Great@insin,这正是我需要的。我希望React Router v1.0很快就能上市。你有一个例子@jonny buchanan吗?很高兴看到有人真的在编写同构应用程序,而不是JU