问题
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 :)
回答1:
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.
回答2:
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.
回答3:
It should be noted that there's an example called auth-flow in react-router repo, that shines light on how this could be done. Although, I'm still trying to make it work for me it is useful to add here.
来源:https://stackoverflow.com/questions/26328949/react-flux-way-to-handle-permission-sensitive-actions-with-login-flows