2015-08-27 35 views
0

我遇到问题更新React中的值。我也会在序言中说我是一个反应的小白,并且仍然试图理解一些概念。反应如何更新道具项目点击,而不是所有项目

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

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

这与注解什么,我试图完成的图像:

http://i.imgur.com/HlhPcym.png

任何帮助将不胜感激。

数量组件:

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; 
+0

你可以发布你想渲染的UI的例子吗?截图或其他东西? – Pcriulan

+0

当然,这是一些关于应该发生的注释的图像[http://i.imgur.com/HlhPcym.png](http://i.imgur.com/HlhPcym.png) –

+0

谢谢!现在更清晰了。你能用这张图片更新你的问题吗?由于我要根据我对这张图片的回复,对每个人都会更清楚:) – Pcriulan

回答

2

QuantityInput部件将分别获得同样的quantity,因为你通过他们Product组件quantity状态。

顺便说一句,你没有区分每个quantity,这是非常混乱。这是做这件事的一种方法:

我不会创建一个详细的实施,但这里是主要的点([...]表明你的代码保持不变):

ProductContainer

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

QuantityInput

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)架构的作用,你应该明确地看看它:)

+0

谢谢你的详细足够的例子!也感谢您提出更好的方法来做事情的建议! –

+0

不客气:)如果你决定尝试Flux,也许这个另一个答案可以帮助你:http://stackoverflow.com/questions/28060493/react-flux-and-xhr-routing-caching/32224104#32224104 – Pcriulan

+0

谢谢,我会检查出来!我确实有一个问题,我读了你引用的帖子,但我想确保我理解它。在我尝试访问正确的所有方法(比如'handleIncrement'等等,并将这些保存在实际的''或我只是在'var'定义中传递那些元素,并且只用'{... callbacks}'离开组件调用?我已经尝试了两种方法,但不断地获取'this.props ...'不是函数 –

相关问题