【发布时间】:2016-04-11 11:07:34
【问题描述】:
我有一个使用 Ruby on Rails 和 ReactJS 的工作应用程序,它有四个组件:
- 产品容器
- ProductItem(ProductContainer 的子级)
- 篮子容器
- BasketItem(BasketContainer 的子项)
目前,当在我的产品项目组件中单击“添加到篮子”按钮时,我使用 Ajax 调用来创建新的篮子项目。这工作正常,但状态不会在没有页面刷新的情况下更新,我不确定如何提醒 BasketContainer/BasketItem 它需要重新渲染组件。
我相信我需要在我的 Ajax 调用成功时设置状态,但我不确定如何为另一个组件执行此操作。任何建议将不胜感激。
ProductItem 组件
class ProductItem extends React.Component{
constructor() {
super()
this.state = {
name: '',
price: 0,
code: '',
id: ''
}
}
componentWillMount() {
this.setState({
name: this.props.data.name,
price: this.props.data.price,
code: this.props.data.code,
id: this.props.data.id
})
}
addtoBasket() {
$.ajax({
type: "POST",
url: "/items",
dataType: "json",
data: {
item: {
name: this.state.name,
price: this.state.price,
code: this.state.code
}
},
success: function() {
console.log("success");
},
error: function () {
console.log("error");
}
})
}
render(){
let productName = this.props.data.name
let productPrice = this.props.data.price
let productCode = this.props.data.code
let productImg = this.props.data.image_url
return (
<div className="col-xs-12 col-sm-4 product">
<img src={productImg}/>
<h3 className="text-center">{productName}</h3>
<h5 className="text-center">£{productPrice}</h5>
<div className="text-center">
<button onClick={this.addtoBasket.bind(this)} className="btn btn-primary">Add to Basket</button>
</div>
</div>
)
}
}
BasketItem 组件
class BasketItem extends React.Component{
constructor(props) {
super()
this.state = {
name: '',
price: 0,
code: '',
id: '',
quantity: 1,
}
}
componentWillMount() {
this.setState({
name: this.props.data.name,
price: this.props.data.price,
code: this.props.data.code,
id: this.props.data.id,
})
}
deleteItem() {
let finalUrl = '/items/' + this.state.id;
$.ajax({
type: "DELETE",
url: finalUrl,
dataType: "json",
success: function(response) {
console.log("successfully deleted");
},
error: function () {
console.log("error");
}
})
}
render(){
let itemName = this.props.data.name
let itemCode = this.props.data.code
let itemQuantity = 1
let itemPrice = (this.props.data.price * itemQuantity).toFixed(2)
const itemId = this.props.data.id
return(
<tr>
<td>{itemName}</td>
<td>{itemCode}</td>
<td>{itemQuantity}</td>
<td><button className="btn btn-warning" onClick={this.deleteItem.bind(this)}>Remove</button></td>
<td>£{itemPrice}</td>
</tr>
)
}
}
ProductContainer 组件
class ProductContainer extends React.Component {
constructor() {
super()
this.state = {
products: []
}
}
componentWillMount() {
this.setState( {
products: this.props.products
})
}
render(){
let p = this.state.products
return(
<div>
<h1>Products</h1>
<div className="row">
{p.map(function(product){
return <ProductItem data={product} key={product.id} />;
})}
</div>
</div>
)
}
}
BasketContainer 组件
class BasketContainer extends React.Component{
constructor() {
super()
this.state = {
items: [],
subTotal: 0,
totalPrice: 0,
deliveryPrice: 0
}
}
componentWillMount() {
this.setState( {
items: this.props.items,
})
}
componentDidMount() {
this.calculateTotals();
}
calculateTotals() {
let subtotal = this.state.subTotal
let delivery = this.state.deliveryPrice
for (var i=0; i<this.state.items.length; i++) {
subtotal += Number(this.state.items[i].price);
}
if (subtotal > 90) {
delivery = 0;
} else if (subtotal >= 50 & subtotal < 90 ) {
delivery = 2.95;
} else {
delivery = 4.95;
}
this.setState( {
deliveryPrice: delivery,
subTotal: subtotal,
totalPrice: subtotal + delivery
})
}
render(){
const {
totalPrice,
subTotal,
deliveryPrice
} = this.state;
let i = this.state.items
let basketBlock;
let basketCount;
let basketSubtotal;
let basketDelivery;
let basketTotal;
if (i) {
if (i.length === 1) {
basketCount = (
<span className="basket-count">
({i.length} item)
</span>
)
} else {
basketCount = (
<span className="basket-count">
({i.length} items)
</span>
)
}
basketSubtotal = (
<tr>
<td></td>
<td></td>
<td></td>
<th>Subtotal</th>
<td>£{subTotal.toFixed(2)}</td>
</tr>
)
basketDelivery = (
<tr>
<td></td>
<td></td>
<td></td>
<th>Delivery</th>
<td>£{deliveryPrice.toFixed(2)}</td>
</tr>
)
basketTotal = (
<tr>
<td></td>
<td></td>
<td></td>
<th>Total</th>
<td>£{totalPrice.toFixed(2)}</td>
</tr>
)
basketBlock = (
<div className="col-xs-12">
<div className="well">
<table className="table table-responsive">
<thead>
<tr>
<th>Product</th>
<th>Code</th>
<th>Quantity</th>
<th>Actions</th>
<th>Price</th>
</tr>
</thead>
<tbody>
{i.map(function(item){
return <BasketItem data={item} key={item.id} />;
})}
{basketSubtotal}
{basketDelivery}
{basketTotal}
</tbody>
</table>
</div>
</div>
)
} else {
basketCount = (
<span className="basket-count">
pluralize(0 Items)
</span>
)
basketBlock = (
<div className="col-xs-12">
<div className="well">
<h5>Add an item</h5>
</div>
</div>
)
}
return(
<div>
<h1>Basket {basketCount}</h1>
<div className="row">
{basketBlock}
</div>
</div>
)
}
}
页面索引 - 组件安装到视图中的位置
<div class="container-fluid">
<div class="row">
<div class="col-xs-12 col-sm-8">
<%= react_component('ProductContainer', render( template: 'products/index.json.jbuilder')) %>
</div>
<div class="col-xs-12 col-sm-4 basket">
<%= react_component 'BasketContainer', render( template: 'items/index.json.jbuilder') %>
</div>
</div>
【问题讨论】:
标签: ruby-on-rails ruby ajax reactjs components