【问题标题】:Remove item from cart React从购物车中移除商品
【发布时间】:2018-07-22 02:51:42
【问题描述】:

关于以下代码,我有 2 个问题。我想在 React 中从我的购物车中删除特定物品。 (后端 Rails)。我知道拼接方法是最常用的方法之一,但在我的情况下,它不会删除特定的单击项,而是会一直删除最后一项,而不管我单击的是哪一项。 我的第二个问题是,即使项目确实以错误的方式被删除但仍然被删除,我的总计也没有得到更新。 这是代码:

import React, { Component } from 'react';
import BasketPic from './images/cart.png';
import StripePayment from './stripePayment';

class MainBasket extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      toggle: true,
      showBasket: false,
      items: this.props.items

    }
    this.toggleBasket = this.toggleBasket.bind(this)
    this.removeItemFromBasket = this.removeItemFromBasket.bind(this)
    console.log(this.state.items)
  }


  toggleBasket(){
   this.setState({toggle: !this.state.toggle});
  }

  showCheckout(){
    this.setState({showBasket: !this.state.showBasket})
  }


  addItemToBasket(itemId){
    fetch(`http://localhost:3000/books/${itemId}`)
    .then( item => item.json())
    .then( item => {
      this.state.items.push(item);
      this.state.total += item.price;
      this.setState(this.state);
    })
  }

  removeItemFromBasket(itemId){
    var itemToBeDeleted = this.state.items.indexOf(itemId)
    var deleted = this.state.items.splice(itemToBeDeleted, 1)
    this.setState(this.state)  
  }

  render(){
    var count_items = this.props.items.length
    var total = this.props.total
    return(
      <div className="basketInfo">
        <div className="mainBasketDiv">
          <img src={BasketPic} onClick={this.toggleBasket} />
          <strong><p className="itemsCart">{count_items}</p></strong>
          <strong><p className="checkOutConf">CheckOut</p></strong> 
          <div className={"toggleDiv-" + this.state.toggle}>
            <h3>{"Total: " + this.props.total}</h3>
            <span><h4>{"Items: " + count_items }</h4></span>

            <hr/>
              {this.props.items.map( item => 
                <div className="animated fadeInRight" key={"item-" + item.id}>
                  <h2>{item.title}</h2> 
                  <h6 onClick={this.removeItemFromBasket} className="remvProd">{"Remove " + item.title}</h6>
                </div>
              )}       
            <button onClick={function(){this.showCheckout()}.bind(this)}> Check out</button>    
          </div>  
        </div>

        <div className="container">
          <div className={"checkOutStripe-" + this.state.showBasket}>
            <div className="totalBar">
              <p className="totalBarTypography"> Total {this.props.items.length} {this.props.items.length < 2 ? "item" : "items"}</p>
              <p className="totalBarTypography"> Total {this.props.total} GBP</p>
            </div>
            <div className="row">
              {this.props.items.map(eachItem => 
                <div className="col-sm" key={"eachItem-" + eachItem.id}>
                  <img src={eachItem.image.url} className="checkOutImg"/>
                  <div className="prodDetails">
                    <h3>{"Product: " + eachItem.title }</h3>
                    <h3>{"Price: " + eachItem.price }</h3>
                  </div>
                </div>
              )}
            </div>
            <div>
              <StripePayment 
                description={'BooksMania'}
                amount={total}
              />
            </div>
          </div>
        </div>
      </div> 
    )
  }
}

// module.exports = MainBasket;
export default MainBasket;

这是我设置总计和项目初始状态的代码:

import React, { Component } from 'react';
import BuyButton from './images/buyButton.jpg';
import MainBasket from './mainBasket';
import CheckOutBasket from './checkOutBasket';
import Reviews from './reviews';

class EachBook extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      newReview: [],
      items: [],
      total: 0
    }
  }

  seeAllReviews(bookId){
    fetch(`http://localhost:3000/books/${bookId}/reviews`)
    .then( reviews => reviews.json())
    .then( reviews => {
      this.setState({
        bookReviews: reviews
      })
    })
  }

  addReview(bookId){ 
    fetch(`http://localhost:3000/books/${bookId}/reviews`,{
      method: 'POST',
      mode: 'cors',
      body: JSON.stringify({comment: this.refs.comment.value}),
      headers: new Headers({
        'Accept': 'application/json',
        'Content-Type': 'application/json',
        'X-CSRF-Token' : this.props.parent.props.parent.props.csrf
      }),
      credentials: 'same-origin'
    }).then(response => response.json())
    .catch(error => alert("There is something wrong with this request"))
    .then( response => {
     this.setState({newReview: response})
    })
  }

  addItemToBasket(itemId){
    fetch(`http://localhost:3000/books/${itemId}`)
    .then( item => item.json())
    .then( item => {
      this.state.items.push(item);
      this.state.total += item.price;
      this.setState(this.state);
    })
  }

  render(){
    return(
      <div>

       <MainBasket items={this.state.items}  total={this.state.total} parent={this}/>
        <div className="container"> 
          {this.props.singleBook.map(indBook =>   
            <div className="indBook" key={indBook.id}>
              <h1>{indBook.title}</h1> <br />
              <h2>{"Author: " + indBook.author}</h2> <br />
              <h4>{"Genre: " + indBook.genre}</h4>
              <h4>{"Price: " + indBook.price}£</h4>
              <img src={indBook.image.url} />
              <div className="button"><img src={BuyButton} onClick={function(){this.addItemToBasket(indBook.id)}.bind(this)}/></div>
              <div className="description">{indBook.description}</div>
              <h3>{this.state.newReview.comment}</h3>
              <div> 
                <h4>Leave a new review</h4> 
                  <textarea ref="comment" type="text" placeholder='Tell us your thoughts '></textarea>
                  <button onClick={ function(){this.addReview(indBook.id)}.bind(this) } >Submit</button>       
              </div>
            </div>
          )}   
        </div> 
      </div>   
    )
  }          
}

export default EachBook;

非常感谢您的帮助!

【问题讨论】:

  • 我对@9​​87654323@ 了解不多,但是对于您的第一个问题,splice 期望索引作为第一个参数,因此您的this.state.items.splice(itemToBeDeleted, 1) 应该是this.state.items.splice(indexOfItemToBeDeleted, 1)
  • 为什么要将你的项目传递给 MainBasket,然后将该数组存储在 MainBasket 中的状态中?这违反了 React 的核心原则之一,即“提升”状态到父组件。如果您确实继续在 MainBasket 中设置新状态,那么它已经与其当前父组件存储的项目表示不同步。如果出于某种原因这是您的意图,也许我错过了。
  • 谢谢大家的及时回答@Subas
  • 谢谢大家的及时回答@Subash 我认为 React 会理解特定元素的 id 也与理解它的索引相关,但显然不是,所以它删除了最后一个一直都是元素。我需要想办法找到索引。
  • @Daniel Zuzevich 我仍然是 React 的初学者(到目前为止大约 4 周)我确信我做的事情不是非常“最佳实践”,但我会纠正它们。我的 Main Basket 仅呈现 items 。项目的状态在我的 Each Book 组件中。但正如你所说,我把那个状态“提升”了,因为我需要参考项目的状态,这样我就可以对它们使用我的删除功能。你认为最好怎么做?非常感谢!

标签: ruby-on-rails arrays reactjs shopping-cart setstate


【解决方案1】:

你最大的问题是你正在改变状态中的items,所以状态不会导致重新渲染。我会考虑使用filter 而不是splice,然后像这样设置items

removeItemFromBasket(itemId) {
  const items = this.stat.items.filter(item => item.id !== itemId)

  this.setState({ items })
}

addItemToBasket 也应该有这个问题。你不应该改变state,因为JavaScript 通过引用传递对象。您应该在 render 方法中使用 this.state.total 而不是 this.props.total

希望对您有所帮助。

【讨论】:

  • 非常感谢这个解决方案,它确实有意义并且非常优雅,但不幸的是它什么也没做,我不明白原因。我使用 this.props.total 以便我可以在我的篮子图片和我的条带组件中呈现总计,因为实际状态会在每个 Book 组件中呈现。再次感谢您的宝贵时间:)
  • 你可能想要重新组织你的组件并且让MainBasket不是有状态的并且只是从你的EachBook组件中传递所有的东西。问题是您正在更新state,但您使用的是props。您可能只想将一些处理程序传递给MainBasket 并让包装组件实际处理状态。
猜你喜欢
  • 1970-01-01
  • 2015-07-05
  • 1970-01-01
  • 2018-10-19
  • 2013-10-17
  • 1970-01-01
  • 2021-07-26
  • 1970-01-01
相关资源
最近更新 更多