【问题标题】:Update two components no relationship Ruby on Rails & ReactJS更新两个组件没有关系 Ruby on Rails & ReactJS
【发布时间】:2016-04-11 11:07:34
【问题描述】:

我有一个使用 Ruby on Rails 和 ReactJS 的工作应用程序,它有四个组件:

  1. 产品容器
  2. ProductItem(ProductContainer 的子级)
  3. 篮子容器
  4. 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


    【解决方案1】:

    您需要使用从父母组件到孩子的回调方法,并在孩子的 ajax 调用成功时更新父母。

    例子

        //Parent component
    
        handleCallback: function(data) {
            // refresh the list
        },
        <somecomponent onSuccess={this.handlecallback} /> //call to child component
    
       // Child Component
    
       ajax.success(){
        this.props.onSuccess(datafromresult);
       }
    

    这应该可以解决您的问题:)

    【讨论】:

    • 嘿阿米特,再次感谢您的回复。 :) 您指的是哪个子组件和父组件?
    • 您要更新的组件将是您有孩子的组件。所以很简单。在您的情况下,BasketContainer Component 是父级,而 BasketItem 是子级。 :)
    • 我认为这不会起作用,因为添加到购物篮按钮位于 ProductItem 组件中,然后 HandleCallback 函数将位于 BasketContainer 组件中。在 Rails 中,它们分别添加到视图中,因此它们之间似乎没有关系。我会将视图添加到问题中,以便您了解我的意思:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多