【问题标题】:this.setState not re-rendering view ReactJS and Ruby on Railsthis.setState 不重新渲染视图 ReactJS 和 Ruby on Rails
【发布时间】:2016-04-11 13:06:27
【问题描述】:

我有一个带有两个 reactJS 组件(不是父/子)的 rails 应用程序,它们当前通过全局事件 Pub/Sub 系统进行通信。

但是,当我运行this.setState({ items: this.props.items }) 时,我收到了Cannot read property 'items' of undefined 的消息。

如果有人能就我为什么会收到此错误提供任何帮助,我们将不胜感激。

我的基本设置是:

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.token = PubSub.subscribe('ADD_BASKET', this.handleUpdate)
    this.token = PubSub.subscribe('REMOVE_ITEM', this.handleUpdate)
    this.calculateTotals();
}

componentWillUnmount() {
PubSub.unsubscribe(this.token)
}

handleUpdate(msg, data){
    console.log(msg)
    this.setState({
        items:this.props.items // ERROR MESSAGE - Cannot read property 'items' of undefined
    })
}
.... Rest of file

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(data) {
            PubSub.publish('ADD_BASKET', data); // THIS WORKS FINE
            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 - 从 Basket Publisher 中删除

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(data) {
            PubSub.publish('REMOVE_ITEM', data); // THIS WORKS FINE
        },
        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>
    )
}
}

【问题讨论】:

    标签: javascript jquery ruby-on-rails reactjs setstate


    【解决方案1】:

    我认为问题在于以下代码行

    this.token = PubSub.subscribe('ADD_BASKET', this.handleUpdate)
    

    您作为参数传递的函数需要与 'this' 绑定

    this.token = PubSub.subscribe('ADD_BASKET', this.handleUpdate.bind(this))
    

    对于 REMOVE_ITEM 操作也是如此。然后应该很好去:)

    【讨论】:

    • 感谢您的帮助 - 这已经消除了错误,但 setState 似乎没有重新渲染组件,知道为什么会这样吗? :)
    • 在 BasketContainer 中,componentWillMount() 您正在使用 this.props.items 设置状态,在 handleUpdate() 中您正在执行相同操作。所以,那里的状态没有改变。
    • componentWillMount 在渲染方法执行之前被调用。需要注意的是,在这个阶段设置状态不会触发重新渲染。在handleUpdate()中,你需要根据'data'参数来操作this.state.items,然后相应地设置状态。
    • 嘿,我用过 this.state.items.push(data);在调用 setState 之前推送数据,这很好用。在我从 items 数组中删除一个项目的情况下,我会怎么做?非常感谢您的帮助
    • 为此,您需要从 this.state.items 数组中删除该“数据”。我假设参数“数据”必须具有任何唯一属性,即“id”或“代码”。所以,你可以这样做,让 newStateItems = this.state.items.filter((i) => i.id != data.id); this.setState({items:newStateItems});
    【解决方案2】:

    您应该将属性 items 从其父类传递给 BasketContainer。这就是为什么您收到错误Cannot read property 'items' of undefined.

    更新:你提到错误的那一行,你得到的错误是因为this的引用错误;

    尝试类似:

    handleUpdate(msg, data){
        var self = this;
        this.setState({
            items: self.props.items // Here get props from self variable
        })
    }
    

    【讨论】:

    • 感谢您的帮助。 BasketContainer 没有父类,这就是我使用 Pub/Sub 事件系统的原因。 Rohit 下面的评论已经消除了错误,但现在 setState 没有重新渲染。知道为什么会这样吗?
    猜你喜欢
    • 1970-01-01
    • 2011-08-02
    • 1970-01-01
    • 1970-01-01
    • 2017-05-07
    • 2011-01-18
    • 2015-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多