从购物车中移除商品

Posted

技术标签:

【中文标题】从购物车中移除商品【英文标题】: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 组件中。但正如你所说,我把那个状态“提升”了,因为我需要参考项目的状态,这样我就可以对它们使用我的删除功能。你认为最好怎么做?非常感谢! 【参考方案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 并让包装组件实际处理状态。

以上是关于从购物车中移除商品的主要内容,如果未能解决你的问题,请参考以下文章

Vue.js实例:开发购物车

Vue.js实例:开发购物车

cookie使用举例(添加购物车商品_移除购物车商品)

List中移除数据某条不需要的数据

angularjs购物车练习

VUE学习笔记:6.阶段练习之购物车案例讲解