【问题标题】:Understanding how to implement a Flux architecture using Flummox了解如何使用 Flummox 实现 Flux 架构
【发布时间】:2015-07-05 04:05:51
【问题描述】:

我目前有一个非常简单的 React 应用程序,它使用状态来确定几个视图。单击提交元素会触发对传递登录或注册凭据的端点的简单调用。我可以继续使用 React 和从服务器返回的 JSON 来确定我的视图,但我知道这不是处理数据的正确方式。

我的问题是,从这里开始,如何使用 Flummox 实现 Flux 模式?我是否使用有效负载触发操作并在操作或存储中进行 API 调用?我试图了解从 UI 中的操作到 API 调用,再到获取响应和 UI 响应商店更改的正确方法。

下面是我的 Auth 组件的代码。我想看一个关于如何在如此简单的情况下使用 Flummox 的示例,这样我就可以了解扩展和添加功能需要什么。

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;

【问题讨论】:

    标签: reactjs reactjs-flux flux flummox


    【解决方案1】:

    在深入研究 Flux 之前,我建议您清理现有的 React 代码。

    作为开始,我会尽量减少组件自身的状态。例如,您可以将单个screen 作为状态,而不是为loginregister 设置单独的状态,它接受您正在渲染的实际屏幕/视图的字符串值(登录/注册)。

    此外,renderLogin()renderRegister() 各自作为组件更好。因此,您的 Auth 组件最终将成为控制器视图。

    同时表单处理看起来过于冗长:您已经为每个字段定义了单独的处理程序,但是单个 handleChange() 就足够了(您可以在输入元素中设置 name="&lt;state-field-name&gt;" 以引用您所在的状态字段引用)。


    在您可以开始使用 Flummox 构建通量模式并将您的应用状态(而不是本地组件状态)移动到商店之后。

    我假设您有 read the docs,但总而言之,Flummox 提供了 StoreAction 帮助器来对应用程序的数据(真实来源)和 UI 操作进行建模。

    动作模块可能如下所示:

    import { Actions } from 'flummox';
    
    
    export default class AuthActions extends Actions {
    
      gotoScreen(screenName) {
        return screenName;
      }
    
      register(requestBody) {
        // Here you deal with your authentication API,
        // make async requests and return a promise.
        // This part is specific to your backend.
        return AuthAPI.register(requestBody)
                      .then(
                        (value) => Promise.resolve(value),
                        (reason) => Promise.reject(reason)
                      );
      }
    
    }
    

    AuthStore 将是事实的来源,即处理实际的应用程序状态。这会注册到操作中,因此它知道在操作发出更改时如何更新自己。

    import { Store } from 'flummox';
    
    
    export default class AuthStore extends Store {
    
      constructor(flux) {
        super();
    
        let authActions = flux.getActions('auth');
    
        // Here you register the functions which will take care
        // of handling the actions and update the store's state.
        // These can be sync or async.
        this.register(authActions.gotoScreen, this.handleGotoScreen);
        this.registerAsync(authActions.register, this.handleRegisterBegin,
                                                 this.handleRegisterSuccess,
                                                 this.handleRegisterError);
    
        // This is the initial state of your flux store
        this.state = {
          screen: 'login',
          // ... any extra state your app might need
        };
      }
    
    
      /* Screen handling */
    
      handleGotoScreen(screenName) {
        this.setState({screen: screenName});
      }
    
      /* Register */
    
      handleRegisterBegin(requestBody) {
        this.setState({
          // change state based on action
        });
      }
    
      handleRegisterSuccess() {
        this.setState({
          // change state based on action
        });
      }
    
      handleRegisterError(errors) {
        this.setState({
          // change state based on action
        });
      }
    
    }
    

    这些需要封装在一个Flux 对象中,然后可以从您应用中的任何位置引用该对象。

    import { Flummox } from 'flummox';
    
    import AuthActions from './AuthActions';
    import AuthStore from './AuthStore';
    
    
    export default class Flux extends Flummox {
    
      constructor() {
        super();
    
        this.createActions('auth', AuthActions);
        this.createStore('auth', AuthStore, this);
      }
    
    }
    

    但是您的视图如何知道商店的状态? preferred way 使用 FluxComponent 将您的商店与视图粘合在一起,当使用 FluxComponent 时,它将通过道具接收商店的状态。

    FluxComponent 接收您的应用程序的Flux 对象的实例,您还需要指定它要连接到哪些商店。

    import Flux from './Flux';
    let flux = new Flux();
    
    <FluxComponent flux={flux} connectToStores={['auth']}>
      <Auth />
    </FluxComponent>
    

    状态作为 props 传递,你可以像平常使用 props 一样直接引用值。

    同时,这允许访问底层视图中的 flux 属性,这使我们能够访问操作,因此能够在用户交互发生时触发它们:

    // You can fire actions from anywhere in your component
    this.props.flux.getActions('auth').gotoScreen('register')
    

    这样结束(或开始)通量循环。

    【讨论】:

    • 这正是我正在寻找的解释类型。感谢您抽出宝贵时间详细说明该过程,并建议如何重构该简单组件的冗长性。
    猜你喜欢
    • 2017-10-06
    • 2021-07-05
    • 2016-01-05
    • 2015-08-02
    • 2015-06-26
    • 2019-10-16
    • 1970-01-01
    • 2011-09-27
    • 2018-07-28
    相关资源
    最近更新 更多