title: How to Handle Post Request in Isomorphic React + React Router Application
body: <p>I want to build Isomorphic <code>react</code> + <code>react-router</code> application and after a few days googling, now I can achieve isomorphic application that only handles GET request. </p>
  
  <p>Here's what I've done so far:</p>
  
  <ol>
  <li>Server use <code>react-router</code> to handle all request</li>
  <li><code>react-router</code> will call <code>fetchData</code> functions that resides in each React View that matches the route.</li>
  <li>Set the data fetched before into props of the React View and render it into <code>string</code></li>
  <li>Inject the <code>string</code> and data fetched before as global variable <code>window.__STATE__</code> into HTML and deliver the HTML to the client</li>
  <li>We have successfully render React App from the server</li>
  <li>When the client finished loading our React App javascript, it will try to render. But we pass the state from <code>window.__STATE__</code> as the props of our React App, and React will not re-render because the state is the same</li>
  </ol>
  
  <p>The problem is it will not work with POST/PUT/DELETE/WHATEVER request. When handling GET request, <code>react-router</code> have information about <code>params</code> and <code>query</code>. For example if we have a route: <code>/user/:uid</code> and client request this url: <code>/user/1?foo=bar</code>, then <code>params</code> would be: <code>{uid: 1}</code> and <code>query</code> would be <code>{foo: 'bar'}</code></p>
  
  <p><code>react-router</code> then can pass it down to <code>fetchData</code> function so it will know to fetch user with <code>uid</code> of 1 and do whatever with <code>foo</code> query.</p>
  
  <p>While in POST request, <code>react-router</code> doesn't know about the POST parameters. On Server, of course we could pass the POST parameters to <code>fetchData</code> function, but what about the Client? It doesn't know what the POST parameters are.</p>
  
  <p>Is there a way that the server could tell the Client about the POST parameters? 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.</p>
  
  <p>fetchData.js</p>
  
  <pre><code>import whenKeys from 'when/keys';
  
  export default (authToken, routerState) =&gt; {
    var promises = routerState.routes.filter((match) =&gt; {
      return match.handler.fetchData;
    }).reduce((promises, match) =&gt; {
      promises[match.name] = match.handler.fetchData(authToken, routerState.params, routerState.query);
      return promises;
    }, {});
  
    return whenKeys.all(promises);
  }
  </code></pre>
  
  <p>server.js</p>
  
  <pre><code>...
  app.use((req, res) =&gt; {
    const router = Router.create({
      routes,
      location: req.originalUrl,
      onError: next,
      onAbort: (abortReason) =&gt; {
        next(abortReason);
      }
    });
  
    router.run((Handler, state) =&gt; {
      fetchData(authToken, state).then((data) =&gt; {
        // render matched react View and generate the HTML
        // ...
      })
    });
  });
  ...
  </code></pre>
  
  <p>login.jsx</p>
  
  <pre><code>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) =&gt; {
           transition.redirect(`/dashboard`);
         });
       );
    }
  
    render() {
      return (
        &lt;DocumentTitle title="Login"&gt;
          &lt;div className="alert alert-danger"&gt;{this.state.error}&lt;/div&gt;
          &lt;form method="post"&gt;
            &lt;input type="text" name="username" value={this.state.username}  onChange={this._onFieldChange('username')} placeholder="Username" /&gt;&lt;br /&gt;
            &lt;input type="password" name="password" value={this.state.password}  onChange={this._onFieldChange('password')} placeholder="Password" /&gt;&lt;br /&gt;
            &lt;button type="submit"&gt;Login&lt;/button&gt;
          &lt;/form&gt;
        &lt;/DocumentTitle&gt;
      );
    }
  
    _onFieldChange(name) {
      var self = this;
      return (e) =&gt; {
        e.preventDefault();
        var nextState = {};
        nextState[name] = e.target.value;
        self.setState(nextState);
      }
    }
  }
  </code></pre>