21

我正在玩一些反应来构建“添加到购物车按钮”。这是我的代码。

var ProductPurchase = React.createClass({
  handleSubmit: function(e){
    e.preventDefault();
    $.ajax({
      url: "/cart/add.js",
      method: "post",
      dataType: "json",
      data: {
        "id": this.props.variantId,
        "quantity": this.props.quantity,
      },
      success: function(data) {
        // emit cart added event
      }.bind(this),
      error: function(xhr, status, err) {
        // emit error event (cart added)
      }.bind(this)
    });
  },
  getDefaultProps: function(){
    return {
      quantity: 1,
      variantId: 231634908,
      buttonText: "Add to cart"
    }
  },
  render: function() {
    return (
      <div className="productPurchase">
        <form action="/cart/add" method="post" enctype="multipart/form-data" onSubmit={this.handleSubmit}>
          <input type="hidden" name="quantity" value={ this.props.quantity } />
          <input type="hidden" name="id" value={ this.props.variantId } />
          <button type="submit">{this.props.buttonText}</button>
        </form>
      </div>
    );
  }
});

我很好奇的是这个 ajax 处理程序。我很确定反应的重点是组件之间的互操作性,但我不知道将这些事件引向何处。我可以想象几个不同的组件,例如成功时的购物车计数指示器或失败时的错误警报,但我不完全知道如何利用这些组件。这就是flux调度员的重点吗?

4

4 回答 4

19

是的,它肯定是 Flux 调度程序的一部分——或者任何你想使用的事件发射器。

不过,在你走这条路之前,很容易将事件处理程序作为道具传递,而不使用 Flux 或自定义事件发射器——就像你对普通 DOM 元素使用onSubmitonClick等处理程序一样。然后让父母处理设置状态,并可能将其传达给其他孩子(通过道具)。

所以在这种情况下,想象一个处理事件的父组件:

var RootComponent = React.createClass({
  handleCartAdded: function(cart) {
    console.log('Got a new cart: ' + cart);
  }
  handleError: function(err) {
    console.error(err)
  }
  render: function() {
    return (
      <ProductPurchase onCartAdded={this.handleCartAdded} onError={this.handleError} />
    )
  }
})

然后您的ProductPurchase组件的相关部分将是:

  success: function(data) {
    this.props.onCartAdded(data)
  }.bind(this),
  error: function(xhr, status, err) {
    this.props.onError(err)
  }.bind(this)

一个更复杂的例子是将结果传递给另一个子组件——但同样,由父组件来管理它:

var RootComponent = React.createClass({
  handleCartAdded: function(cart) {
    this.setState({cart: cart})
  }
  handleError: function(err) {
    console.error(err)
  }
  render: function() {
    return (
      <div>
        <ProductPurchase onCartAdded={this.handleCartAdded} onError={this.handleError} />
        <CartSummary cart={this.state.cart} />
      </div>
    )
  }
})

通过这种方式,组件彼此解耦——数据/函数只能通过明确的合约(props)传入。

这种简单的事件处理风格更加明确且更易于调试 - 因此,如果您的应用程序变得非常复杂和/或您有很多组件都需要与每个组件进行通信,我真的只会求助于 Flux 风格的架构其他以复杂的方式。

于 2014-12-14T20:43:59.950 回答
7

Flux 用于解耦编程结构(包括 AJAX 调用)。

这是来自Flux Docs的图表

通量架构图

Flux 架构中的Dispatcher始终保持在全局范围内。因此,与调度程序相关的任何操作总是发生在全局范围内。此外,调度程序和事件系统略有不同,事件系统总是注册绑定到特定事件的回调,但在调度程序的情况下,所有回调都绑定到所有事件。

如何使用调度程序?(不使用 Stores 和 ActionCreators 的简化方法)

  1. 如果应用程序的其他部分受到此 AJAX 调用的影响,那么您不应从该组件进行此 AJAX 调用,而应将 AJAX 调用移动到新文件和函数中。例如使用 CommonJS,

    // CartApiUtils.js
    module.exports = {
        addToCart: function(item){
            // AJAX call
        }
    }
    
  2. 使用 Flux 的Dispatcher 类创建一个 AppDispatcher(在整个应用程序中很常见)

    var appDispatcher = new Dispatcher();
    
  3. 在 addToCart() 函数中,在成功的 AJAX 响应时,使用 AppDispatcher 调度事件:

    appDispatcher.dispatch({
        actionType: 'cart.newItemAdded',
        data: dataFromAjax
    });
    
  4. 在您的应用程序中,无论您想在哪里使用此事件,您都可以注册一个函数到调度程序。

    appDispatcher.register(function(payload){
        if(payload.actionType === 'cart.newItemAdded'){
            // payload.data contains the data
        }
    });
    

这是一种简化的方法。在更规范化的结构和更大的应用程序中,您应该使用 Stores(类似于 MVC 的模型层,但不完全相同)和 ActionCreator,其中视图层上的任何交互都是用户的操作和 AJAX 调用的任何响应也成为服务器的一个动作。

经验法则是,必须从 Store 填充(或更新)视图,并且必须根据 Dispatcher 事件更新 Store。

于 2014-12-14T20:40:40.547 回答
2

使用 npm 的“ react-global-events ”怎么样?

https://www.npmjs.com/package/react-global-events

于 2017-05-04T14:09:16.827 回答
0

Flux 是维护模式,所以如果你打算构建一个生产就绪的应用程序,我不建议你这样做。替代方案是 Redux 或 MobX,不过我总是使用React 的内置 Context来处理全局状态 - 易于实现并且像魅力一样工作。

于 2021-07-03T10:54:55.380 回答