使用登录流处理权限敏感操作的 React/Flux 方式

Posted

技术标签:

【中文标题】使用登录流处理权限敏感操作的 React/Flux 方式【英文标题】:React/Flux way to handle permission sensitive actions with login flows 【发布时间】:2014-12-07 08:47:28 【问题描述】:

我一直在使用 React/Flux,但在处理对权限敏感的操作时无法理解“Flux 方式”。

总体问题: 当未登录的访问者尝试要求他/她登录的操作时,Flux 的方式是什么(a)检查用户是否已登录,(b)启动登录流程,(c)完成对成功采取行动?

以论坛应用为例,需要用户登录才能发帖:

我们有一个评论表单组件(主要取自 FB 的 React tut):

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>
    )
  
);

一家 cmets 商店(缩写)

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;
  )
);

还有一个用于处理会话的商店(也简称为):

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;
  )
);

我最初的想法是,这是 Flux 的 waitFor() 方法的一个案例。但是,上面的实现失败了,因为waitFor 会在设置SessionStore.dispatchToken 后立即关闭依赖循环(只要ensureCurrentUser 返回)。

在这种情况下,负载应该传递到ensureCurrentUser,然后传递到/login 的路由处理程序中吗?处理这些类型的流的 Flux 方式是什么?

提前致谢:)

【问题讨论】:

【参考方案1】:

正如 FakeRainBrigand 在他的回答中所建议的那样,您只需通过首先从 SessionStore 检索该值来检查用户是否具有有效会话,然后再创建评论:

case CommentConstants.ADD_COMMENT:
  if (SessionStore.getUser()) 
   createComment(action.data);
  
  break;

但为了保留评论以便在用户登录后创建它,我会在 CommentStore 中创建一个待处理的 cmets 集合,然后在对登录验证和会话创建的回调中,调度一个新操作通知 CommentStore 用户现在已经登录。然后 CommentStore 可以通过从待处理的 cmets 中创建真正的 cmets 来响应。

【讨论】:

问题中的代码还有一些其他不相关的问题:在 DOM 中保持状态是 React 中的代码异味。这一行:this.refs.content.getDOMNode().value.trim() 应该替换为this.state.content——你应该在this.state 中维护textarea 的状态。另请注意,您的 ContentStore 的 dispatcherIndex 可能应重命名为 dispatchToken 以与 SessionStore 保持一致。 感谢您的额外提示! this.refs.content.getDOMNode().value.trim() 实际上是直接取自 Facebook's React tutorial,在 CommentForm 组件中使用。我是否应该在用户更改评论内容时更新状态,然后在提交时简单地从状态中提取? 嗯,我希望 React 网站上没有那个,因为它与此页面形成对比:facebook.github.io/react/docs/forms.html - 这更接近我处理输入的方式,我在其中维护本地组件的this.state 中的值。另请参阅 Flux-TodoMVC 应用程序以获取更完整的示例。 @fisherwebdev:回复:“然后 CommentStore 可以通过从待处理的 cmets 中创建真正的 cmets 来响应”——这在 Flux 中是如何发生的?我认为商店不应该启动网络活动(至少如果您像我按照***.com/questions/25630611/… 那样将商店保持为哑数据存储库)。商店是否应该回调 Action Creator?但我认为商店不应该发起行动?谢谢! @LaneRettig 商店不是哑数据存储库。它们是应用程序的所有逻辑应该驻留的地方。从商店发起网络活动没有任何问题。有些人喜欢从动作创建者发起,有些人喜欢从商店发起。这主要是口味问题。与服务器异步通信的重要一点是响应需要调度一个新的操作,而不是直接在存储中处理。【参考方案2】:

最简单的方法就是询问 SessionStore 是否有会话。

 case CommentConstants.ADD_COMMENT:
    if (SessionStore.getUser()) 
       createComment(action.data);
    
    break;

当然,这只是为您节省了服务器请求。这种行为与总是调用createComment(action.data) 应该没有什么不同。

在这种情况下,负载应该传递给 ensureCurrentUser,然后传递给 /login 的路由处理程序吗?处理这些类型的流的 Flux 方式是什么?

为此,您可能需要一个事件发射器来发出“登录”事件。

 case CommentConstants.ADD_COMMENT:
    if (SessionStore.getUser()) 
       createComment(action.data);
    
    else 
       someEventEmitter.one('login', function()
           createComment(action.data);
       );
       someEventEmitter.emit('loginRequired');
    
    break;

当 loginRequired 被发出时,如果没有用户登录,则会显示登录视图。

【讨论】:

领先我 20 秒 ;D 呵呵,一开始我错过了问题中最重要的部分,所以也许我应该多花 20 秒时间阅读它:-) FakeRainBrigand 在此处关于向 SessionStore 询问与 SessionStore.getUser() 的会话是正确的。不确定我是否完全同意 EventEmitter 的东西,因为它似乎将应用程序变成了一个 pubsub 架构,并且远离了 Flux。如果您试图保留评论以便在用户登录后创建它,我将在 CommentStore 中创建一个待处理的 cmets 集合,然后发送一个操作以通知 CommentStore 用户现在已经登录。然后商店可以通过从待处理的 cmets 中创建真正的 cmets 来对此做出响应。 是的,我倾向于远离纯粹的助焊剂。如果 fisherwebdev 创建了答案,请接受。 我认为你的回答 + 这些 cmets 是可以接受的 :)【参考方案3】:

值得注意的是,react-router repo 中有一个名为auth-flow 的示例,它阐明了如何做到这一点。虽然,我仍在努力让它对我有用,在此处添加很有用。

【讨论】:

以上是关于使用登录流处理权限敏感操作的 React/Flux 方式的主要内容,如果未能解决你的问题,请参考以下文章

React、Flux、React-Router 调度错误 - 可能的批处理更新解决方案?

React+Flux:通知视图/组件操作失败?

React Flux 实现调度链

React + Flux:如何重置商店?

React/Flux - 监控 api 和更新存储新数据的最佳方式?

如何处理 React/Flux 中的保存状态?