I have been playing with React/Flux, and I am having trouble wrapping my head around the 'Flux Way' for handling permission-sensitive actions.
Overarching question: When a non-logged in visitor attempts an action that requires he/she to be logged in, what is the Flux way of (a) checking if a user is logged in, (b) starting the login flow, (c) finishing the action on success?
Take an example of a forum app, that requires users to be logged in to post:
We have a comment form component (mostly taken from FB's React tut) as such:
var CommentForm = React.createClass({
handleSubmit: function ( e ) {
e.preventDefault();
// get data
commentData = {
content: this.refs.content.getDOMNode().value.trim()
};
this.props.onCommentSubmit( commentData );
this.resetForm();
},
resetForm: function () {
this.refs.content.getDOMNode().value = '';
},
render: function () {
return (
<form className="comment-form" id="comment-form" onSubmit={ this.handleSubmit }>
<textarea name="comment[content]" placeholder="What's on your mind?" ref="content"></textarea>
<button className="post-comment button" type="submit">Post</button>
</form>
)
}
});
A comments store (abbreviated)
var CHANGE_EVENT = 'change';
var _comments = {};
function createComment ( data ) {
// post to server
}
var CommentStore = React.addons.update(EventEmitter.prototype, {$merge: {
// omitted methods
dispatcherIndex: AppDispatcher.register(function(payload) {
var action = payload.action;
var text;
switch(action.actionType) {
case CommentConstants.ADD_COMMENT:
AppDispatcher.waitFor([SessionStore.dispatchToken])
createComment(action.data);
break;
}
return true;
})
}});
And a store for handling sessions (also abbreviated):
var CHANGE_EVENT = 'change';
function ensureCurrentUser () {
if ( !SessionStore.currentUser() ) {
app.router.navigate('/login');
}
}
var SessionStore = React.addons.update(EventEmitter.prototype, {$merge: {
// omitted code
currentUser: function () {
return app.context.current_user;
},
dispatchToken: AppDispatcher.register(function ( payload ) {
var action = payload.action;
switch(action.actionType) {
case CommentConstants.ADD_COMMENT:
ensureCurrentUser();
break;
}
return true;
})
}});
My initial thought was that this is a case for Flux's waitFor()
method. However, the implementation above fails, as waitFor
closes the dependency loop as soon as SessionStore.dispatchToken
is set (as soon as ensureCurrentUser
returns).
Is this a case where the payload should be passed into ensureCurrentUser
, and then into the route handler for /login
? What is the Flux way of handling these types of flows?
Thanks in advance :)
As FakeRainBrigand suggested in his answer, you'd want to just check that the user has a valid session before creating a comment by first retrieving that value from the SessionStore:
case CommentConstants.ADD_COMMENT:
if (SessionStore.getUser()) {
createComment(action.data);
}
break;
But to preserve the comment so that it gets created after the user logs in, I would create a collection of pending comments in the CommentStore, and then later, in a callback to the login verification and session creation, dispatch a new action to inform the CommentStore that the user has now logged in. Then the CommentStore can respond to that by creating real comments out of the pending ones.
The simplest would be just asking SessionStore if there's a session.
case CommentConstants.ADD_COMMENT:
if (SessionStore.getUser()) {
createComment(action.data);
}
break;
Of course, this just saves you a server request. The behavior shouldn't be any different than always calling createComment(action.data)
.
Is this a case where the payload should be passed into ensureCurrentUser, and then into the route handler for /login? What is the Flux way of handling these types of flows?
For this, you might want to have an event emitter that emits a 'login' event.
case CommentConstants.ADD_COMMENT:
if (SessionStore.getUser()) {
createComment(action.data);
}
else {
someEventEmitter.one('login', function(){
createComment(action.data);
});
someEventEmitter.emit('loginRequired');
}
break;
And when loginRequired is emitted, if there isn't a user logged in, the login view would be presented.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With