I currently have a very simple React app that uses state to determine a couple of views. Clicking on the submit element fires a simple call to an endpoint passing either login or registration credentials. I could continue down this road to use React and JSON returned from the server to determine my views, but I am aware this is not proper the way to handle data.
My question is, from here, how do I implement a Flux pattern using Flummox? Do I fire an action with the payload and make my API call in the action or the store? I'm trying to understand the proper way to make this roundtrip from an action in my UI, to my API call, to getting the response and the UI responding to a change on the store.
Below is code for my Auth component. I would like to see an example on how to use Flummox in a situation as simple as this, so I can understand what's needed to scale and add features.
Auth.jsx
'use strict';
var React = require('react');
var request = require('request');
var Auth = React.createClass({
getInitialState: function() {
return {
name: '',
email: '',
pass: '',
passConfirm: '',
login: true,
register: false
};
},
handleLogin: function(){
this.setState({
login: true,
register: false
});
},
handleRegister: function(){
this.setState({
register: true,
login: false
});
},
handleName: function(event){
this.setState({
name: event.target.value
});
},
handleEmail: function(event){
this.setState({
email: event.target.value
});
},
handlePass: function(event){
this.setState({
pass: event.target.value
});
},
handlePassConfirm: function(event){
this.setState({
passConfirm: event.target.value
});
},
handleSubmit: function(){
var register = {
name: this.state.name,
email: this.state.email,
password: this.state.pass,
confirmPassword: this.state.passConfirm
};
var endpoint = 'http://localhost:3000';
request({
uri: endpoint + '/register',
method: 'POST',
json: register
}, function(error, response, body){
if (error) {
console.log(error);
} else {
console.log(response);
}
});
},
renderLogin: function () {
return (
<form className="login">
<div className="input-container">
<input type='text' value={this.state.email} onChange={this.handleEmail} placeholder="email" />
<input type='password' value={this.state.password} onChange={this.handlePass} placeholder="password" />
</div>
<div className="auth-submit" onClick={this.handleSubmit}>Login</div>
</form>
);
},
renderRegister: function(){
return (
<form className="register">
<div className="input-container">
<input type='text' value={this.state.name} onChange={this.handleName} placeholder="name" />
<input type='email' value={this.state.email} onChange={this.handleEmail} placeholder="email" />
<input type='password' value={this.state.pass} onChange={this.handlePass} placeholder="password" />
<input type='password' value={this.state.passConfirm} onChange={this.handlePassConfirm} placeholder="confirm password" />
</div>
<div className="auth-submit" onClick={this.handleSubmit}>Register</div>
</form>
);
},
render: function(){
var auth = null;
if (this.state.login) {
auth = this.renderLogin();
} else if (this.state.register) {
auth = this.renderRegister();
}
return (
<div className="auth-container">
<div className="auth-logo">Flow</div>
{auth}
<div className="auth-select">
<div className="auth-label-container">
<div className="auth-label" onClick={this.handleLogin}>Login</div>
</div>
<div className="auth-label-container">
<div className="auth-label" onClick={this.handleRegister}>Register</div>
</div>
</div>
</div>
);
},
});
module.exports = Auth;
Before diving into Flux, I'd suggest to clean up the existing React code you have.
As a start I would try to reduce component's own state as much as possible. For example, instead of having separate state for
login
andregister
, you can have a singlescreen
as state, which accepts the string value of the actual screen/view you are rendering (login/register).Also each
renderLogin()
andrenderRegister()
are better off as components on their own. Therefore yourAuth
component would end up being a controller-view.Form handling looks too verbose at the same time: you have defined a separate handler for every single field, but a single
handleChange()
would suffice (you can setname="<state-field-name>"
in your input elements to reference the state field you are referencing).Afer that you can start building the flux pattern using Flummox and moving your app state (and not local component state) into stores.
I assume you have read the docs, but as a summary Flummox offers
Store
andAction
helpers to model your application's data (source of truth) and UI actions.The actions module could look something like this:
And an
AuthStore
will be the source of truth, i.e. handles the actual app state. This registers with actions, so it knows how to update itself whenever a change is emitted by actions.These need to be encapsulated in a
Flux
object which can then be referenced from anywhere in your app.But how do your views know about store's state? The preferred way to glue your stores with views is by using the
FluxComponent
, which would receive the store's state via props when usingFluxComponent
.FluxComponent
receives an instance of your app'sFlux
object, and you also need to specify which stores it wants to connect to.The state is passed as props, and you can reference the values directly as you do with props normally.
At the same time, this allows to access the
flux
prop in the underlying views, which gives us access to actions, and therefore are able to trigger them when user interaction happens:With this finishes (or begins) the flux cycle.