【问题标题】:React how to update props for item clicked and not all items反应如何更新点击项目的道具,而不是所有项目
【发布时间】:2015-11-21 23:41:52
【问题描述】:

我在更新 React 中的值时遇到问题。我还要先声明,我是一个反应新手,但仍在努力掌握一些概念。

我有一个组件,在单击时会增加和减少一个值。问题是它会更新所有项目的所有道具,而不是点击一次。

例如,我有一个项目列表,我单击 1 个项目来更新 quantity 它会这样做,但也会更新其他项目的数量。所有这些项目都是相似的。还需要做的是计算所有项目的所有数量并输出一个也不起作用的总数。

这是一张带有我想要完成的注释的图片:

任何帮助将不胜感激。

数量组件:

import React from 'react';
import If from '../utils/helpers';


var QuantityInput = React.createClass({
  getInitialState: function(props) {
    return {
      quantity: this.props.quantity
    };
  },

  handleIncrement: function(e) {
    this.props.handleIncrement(this.props.quantity + 1);
  },

  handleDecrement: function(e) {
    if (this.props.quantity > 1) {
      this.props.handleDecrement(this.props.quantity - 1);
    }
  },

  handleChange: function(e) {
    this.setState({
      quantity: this.props.quantity
    });
  },

  render: function() {
    return (
      <div className="quantity-input">
        <span className="button button--gray controls__quantity" onClick={this.handleDecrement}>-</span>
        <div className="quantity" onChange={this.handleChange}>{this.props.quantity}</div>
        <span className="button button--gray controls__quantity" onClick={this.handleIncrement}>+</span>
      </div>
    );
  }
});

module.exports = QuantityInput;

产品:

import React from 'react';
import If from '../utils/helpers';
import QuantityInput from '../components/quantity.js'


var Product = React.createClass({
  getInitialState: function() {
    return {
      quantity: 0
    }
  },

  handleIncrement: function(e) {
    this.setState({
      quantity: this.state.quantity + 1
    });
  },

  handleDecrement: function(e) {
    if (this.state.quantity > 1) {
      this.setState({
        quantity: this.state.quantity - 1
      });
    }
  },

  handleChange: function(e) {
    var value = e.target.value.replace(/[^0-9]/, '');

    value = (value == '' ? 1 : value);
    value = parseInt(value);

    this.setState({
      quantity: value
    });
  },

  render: function() {
    var content;
    var self = this;
    if (this.props.items.length > 0) {
      this.props.items.map(function(product) {
        var items = product.priceCode.map(function(priceCode) {
          return (
            <div className="list-item" key={priceCode.priceCode_id}>
              <div className="list-info list-info--cart">
                <div className="list-info__venue">
                  <h3 className="event-title">{priceCode.priceCode_title}</h3>
                  <If condition={priceCode.priceCode_passcode}>
                    <input type="text" placeholder="Passcode" />
                  </If>
                  <span className="event-details">{priceCode.priceCode_info}</span>
                </div>
              </div>
              <div className="controls">
                <div className="list-info__price">${priceCode.priceCode_price}</div>
                <QuantityInput quantity={self.state.quantity} handleChange={self.handleChange} handleIncrement={self.handleIncrement} handleDecrement={self.handleDecrement} />
              </div>
            </div>
          )
        });

        content = {items}
      });
    }

    return (
      <div>
        {content}
      </div>
    );
  }
});

var ProductContainer = React.createClass({
  getInitialState: function() {
    return {
      data: [],
      quantity: 0
    }
  },

  componentWillMount: function() {
    this.loadProducts(this.props.url);
  },

  loadProducts: function(url) {
    $.ajax({
      url: url,
      dataType: 'json',
      success: function(data) {
        this.setState({
          data: data
        });
      }.bind(this),
      error: function(xhr, status, err, data) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
  },

  _hasData: function() {
    var displayedItems = this.state.data.filter(function(product) {
      var match = product.priceCode.filter(function(priceCode) {
        return priceCode.priceCode_title.toLowerCase();
      });

      return (match !== -1);
    }.bind(this));

    return (
      <div>
        <Product items={displayedItems} />
      </div>
    ); 
  }, 

  render: function() {
    if (this.state.data) {
      return (
        <div className="price-code">
          {this._hasData()}
          <div className="subtotal-wrapper">
            <a href="#" className="button button--gray">Clear Selections</a>
            <div className="subtotal">
              Subtotal ({this.state.quantity}):
            </div>
            <a href="#" className="button">Find Tickets</a>
          </div>
        </div>
      )          
    } else {
      return <div>Loading...</div>;
    }

    return false
  }
});

module.exports = ProductContainer;

【问题讨论】:

  • 你能发布一个你想要渲染的 UI 的例子吗?截图什么的?
  • 当然,这是带有一些注释的图像http://i.imgur.com/HlhPcym.png
  • 谢谢!现在清楚了很多。你能用这张图片更新你的问题吗?由于我将根据这张图片进行回复,所以每个人都会更清楚:)
  • 完成,检查问题。谢谢
  • 好吧,这就是我的答案,如果有什么不清楚的地方,请随时告诉我:)

标签: jquery reactjs


【解决方案1】:

您是QuantityInput 的组件将收到相同的quantity,因为您将Product 组件quantity 状态传递给它们。

顺便说一句,你没有区分每个quantity,这很混乱。这是一种方法:

我不会创建详细的实现,但这里是要点([...] 表示您的代码保持不变):

产品容器

var ProductContainer = React.createClass({
  getInitialState: function() {
    return {
      data: [],
      subTotal: 0
    }
  },

  incrementSubTotal: function() {
    this.setState({
        data: this.state.data,
        subTotal: this.state.subTotal + 1
    });
  },

  decrementSubTotal: function() {
    this.setState({
        data: this.state.data,
        subTotal: this.state.subTotal - 1
    });
  },

  _hasData: function() {
    [...]

    return (
      <div>
        <Product 
            items={displayedItems}
            incrementSubTotal={this.incrementSubTotal}
            decrementSubTotal={this.decrementSubTotal}/>
      </div>
    ); 
  }, 

  render: function() {
    [...]
       Subtotal ({this.state.subTotal}):
    [...]
  }
});

产品

var Product = React.createClass({
  //this component is now stateless

  render: function() {
    [...]

    // the following extract items from within this.props and lets the 'incrementSubTotal' and
    // 'decrementSubTotal' in '...callbacks'. See http://facebook.github.io/react/docs/transferring-props.html
    // for details.
    var {items, ...callbacks} = this.props;
    [...]
        <QuantityInput {...callbacks}/>
    [...]

    return (
      <div>
        {content}
      </div>
    );
  }
});

数量输入

var QuantityInput = React.createClass({

  getInitialState: function() {
    return {
      quantity: 0
    }
  },

  handleIncrement: function(e) {
    [...]
    this.props.incrementSubTotal();
  },

  handleDecrement: function(e) {
    [...]
    this.props.decrementSubTotal();
  },

  render: function() {
    return (
      <div className="quantity-input">
        <span className="button button--gray controls__quantity" onClick={this.handleDecrement}>-</span>
        <div className="quantity">{this.state.quantity}</div>
        <span className="button button--gray controls__quantity" onClick={this.handleIncrement}>+</span>
      </div>
    );
  }
});

如您所见,我正在传递回调以从子组件中更新父组件的状态。 这不是一个很好的做法。更好的方法是将所有输入的状态保留在顶级组件上,如果您对 MVC 模型了解一点,则充当“控制器视图”组件。 当单击“+”或“-”按钮时,您的应用程序应触发一个事件,让 ProductContainer 知道某些内容已更改并且必须更新其状态。这正是 (Flux)[https://facebook.github.io/flux/] 架构的作用,你应该明确地看看它:)

【讨论】:

  • 哇,感谢您提供了足够详细的示例!也感谢关于更好的做事方式的建议!
  • 不客气 :) 如果您决定尝试 Flux,也许这个另一个答案可以帮助您:stackoverflow.com/questions/28060493/…
  • 谢谢,我去看看!我确实有一个问题,我阅读了您引用的帖子,但我想确保我理解它。在{...callbacks} 之后,我应该输入我尝试访问的所有方法,例如handleIncrement 等,并将它们保留在实际的&lt;QuantityInput {...callbacks}/&gt; 上,或者我只是传递var 定义中的那些并离开组件只用{...callbacks}单独打电话?我都试过了,但不断收到this.props... is not a function
  • 对于这部分你必须完全按照我写的来写。这是一个 JSX 快捷方式,您可以在此处了解更多信息:facebook.github.io/react/docs/transferring-props.html 另请注意,我没有测试我发布的实际代码,它可能包含一些错字或其他错误,只是为了让您了解一下 :)
  • 啊,好吧,是的,我读过它,但很困惑。不得不再读几遍:)。哈哈,好的,谢谢你的提醒,希望我能从这里弄清楚。再次感谢。
猜你喜欢
  • 1970-01-01
  • 2021-09-28
  • 2021-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多