单击 ReactJS 按钮后 localStorage 被重置

localStorage gets reset after button click ReactJS

我目前遇到的问题是,在尝试将属于不同页面(如下所示)的项目添加到本地存储后,本地存储被重置。本地存储功能正用于购物车功能。

当我尝试添加同一类别的项目时一切正常,但一旦我切换类别,本地存储就会被重置。

我还注意到一个奇怪的行为是,对于我尝试添加到购物车的第一个项目,我必须双击它才能在本地存储中注册。

我已经设置了程序,只有购物车页面需要访问本地存储。

正在添加“可穿戴设备类别”中的产品

返回并进入“计算机”部分中的项目。 忽略边栏

从可穿戴部分添加项目并清除本地存储。

代码: App.js

class App extends Component {
  userData;
  constructor(props) {
    super(props);

    this.state = {
      cart: [],
    };

    this.handleAddToCart = this.handleAddToCart.bind(this);
  }

  handleAddToCart = (productId, prodName, description, price) => {
    console.log(" Handle Add to Cart Called ", productId);
    console.log("->cart state: ", this.state.cart);
    const holder = {
      productId,
      quantity: 1,
      prodName,
      description,
      price,
    };

    const idx = this.indexOfProduct(productId);

    if (idx == -1) {
      // Product does not exist in cart
      this.setState(
        {
          cart: [...this.state.cart, holder],
        },
        () => {
          console.log("Updated Cart: ", this.state.cart);
        }
      );
    } else {
      let newArray = [...this.state.cart];
      newArray[idx] = {
        ...newArray[idx],
        quantity: newArray[idx].quantity + 1,
      };
      this.setState(
        {
          cart: newArray,
        },
        () => {
          console.log("Updated Cart: ", this.state.cart);
        }
      );
    }
    localStorage.setItem("cart", JSON.stringify(this.state.cart));
  };

  indexOfProduct(productId) {
    for (let index = 0; index < this.state.cart.length; index++) {
      if (this.state.cart[index].productId == productId) return index;
    }
    return -1;
  }

  render() {
    return (
      <div className="App">
        {/* <div className="container-fluid">
          <NavBarComponent />
        </div> */}
        <>
          <Router>
            <div className="container-fluid">
              <NavBarComponent />
            </div>

            <Switch>
              <Route exact path="/sidebar">
                <SideBarComponent />
              </Route>
              <Route exact path="/products/:category">
                <ProductGridComponent />
              </Route>
              <Route exact path="/cart">
                <ShoppingCartComponent />
              </Route>
              <Route exact path="/product/:id">
                {/*onAddToCart={this.handleAddToCart} */}
                <ProductViewComponent onAddToCart={this.handleAddToCart} />
              </Route>

              <Route exact path="/contact">
                <ContactUsComponent />
              </Route>

              <Route exact path="/about-us">
                <AboutUsComponent />
              </Route>
              <Route exact path="/">
                <HomeComponent />
              </Route>
            </Switch>
          </Router>
        </>
        <FooterComponent />
      </div>
    );
  }
}

export default App;

ShoppingCartComponent.jsx

class ShoppingCartComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      cart: [],
    };
    console.log("Hello Im the constructor");
  }
  static getDerivedStateFromProps(props, state) {
    console.log("Hello Im the dState Func");

    const sCart = localStorage.getItem("cart");
    const parsedCart = JSON.parse(sCart);

    if (sCart == null) {
      return { cart: [] };
    } else {
      console.log("cart String mount on shopping cart: ", sCart);
      console.log("cart Object at mount on shopping cart: ", parsedCart);
     

      return { cart: parsedCart };
      console.log("After appending", this.state.cart);
    }
  }


  render() {
    console.log("Shopping Cart Array at Render(): ", this.state.cart);
    return (
      <div className="container mt-5 p-3 rounded cart">
        <div className="row no-gutters">
          <div className="col-md-8">
            <div className="product-details mr-2">
              <div className="d-flex flex-row align-items-center">
                <i className="fa fa-arrow"></i>

                <button /* onClick={history.back} */>
                  <span className="ml-2">
                    <a style={{ color: "black" }}>Continue Shopping</a>
                  </span>
                </button>
              </div>
              <hr />
              <h6 className="mb-0">Shopping cart</h6>
              <div className="d-flex justify-content-between">
                <span>
                  You have {this.state.cart.length} items in your cart
                </span>
                <div className="d-flex flex-row align-items-center">
                  <span className="text-black-50">Sort by:</span>
                  <div className="price ml-2">
                    <span className="mr-1">price</span>
                    <i className="fa fa-angle-down"></i>
                  </div>
                </div>
              </div>

              {this.state.cart.map((product) => (
                <div className="d-flex justify-content-between align-items-center mt-3 p-2 items rounded">
                  <div className="d-flex flex-row">
                    <img
                      className="rounded"
                      src="https://i.imgur.com/QRwjbm5.jpg"
                      width="40"
                    />
                    <div className="ml-2">
                      <span className="font-weight-bold d-block">
                        {product.prodName}
                      </span>
                      <span className="spec">256GB, Navy Blue</span>
                    </div>
                  </div>

                  ...
         

ProductGridComponent.jsx //显示每个类别的产品的位置。边栏是一个单独的组件。

class ProductGridComponent extends Component {
  constructor(props) {
    super(props);

    const windowUrl = window.location.pathname.substring(1);
    console.log("window url: ", windowUrl);

    this.state = {
      category: windowUrl.substring(windowUrl.indexOf("/") + 1), //Please fix me, I am vulnerable to SQL Injection
      products: [],
    };
    console.log(this.state.category);

    this.handleShopButtonClick = this.handleShopButtonClick.bind(this);
  }
  componentDidMount() {
    ProductService.getProductsByCategory(this.state.category).then((res) => {
      this.setState({ products: res.data });
    });
  }
  handleShopButtonClick(productId) {
    this.props.history.push(`/product/${productId}`);
  }
  onAddClick() {}

  render() {
    return (
      <>
        {/* <div className="container-fluid page-body-wrapper"> */}
        <div className="wrapper">
          <SideBarComponent />
          <div className="row" style={{ marginLeft: "5px" }}>
            {this.state.products.map((product) => (
              <div className="col col-md-3" style={{ marginTop: "5px" }}>
                <div className="card">
                  <div className="d-flex justify-content-between align-items-center">
                    <div className="d-flex flex-row align-items-center time">
                      <i className=""></i>
                      <small className="ml-1">{product.vendorName}</small>
                    </div>
                  </div>
                  <div className="text-center">
                    <img src="https://i.imgur.com/TbtwkyW.jpg" width="250" />
                  </div>
                  <div className="text-center">
                    <h5>{product.prodName}</h5>
                    <span className="text-success">${product.price}</span>
                  </div>
                  <div>
                    <Link to={`/product/${product.id}`}>
                      <button
                        className="btn btn-outline-dark flex-shrink-0"
                        type="button"
                        style={{ marginLeft: "10px" }}
                      >
                        <i
                          className="bi-bag-fill me-1"
                          style={{ marginRight: "4px" }}
                        ></i>
                        Buy Now
                      </button>
                    </Link>
                    <Link to={`/product/${product.id}`}>
                      <button
                        className="btn btn-outline-dark flex-shrink-0"
                        type="button"
                        style={{ marginLeft: "10px" }}
                      >
                        <i className=""></i>
                        View
                      </button>
                    </Link>
                  </div>
                </div>
              </div>
            ))}
            {/* <img src="https://i.imgur.com/aTqSahW.jpg" width="250" /> */}
          </div>
        </div>
      </>
    );
  }
}

export default ProductGridComponent;

ProductViewComponent.jsx

class ProductViewComponent extends React.Component {
  constructor(props) {
    super(props);

    const windowUrl = window.location.pathname.substring(1);
    console.log("window url for product: ", windowUrl);

    this.state = {
      //id: this.props.match.params.id,
      id: windowUrl.substring(windowUrl.indexOf("/") + 1), //Please fix me, I am vulnerable to SQL Injection
      name: "",
      price: 0,
      vendor: "holder vendor",
      description: "",
    };
    console.log("ID: ", this.state.id);
  }

  componentDidMount() {
    ProductService.getProductById(this.state.id).then((res) => {
      let product = res.data;

      this.setState({
        name: product.prodName,
        price: product.price,
        vendor: product.vendorName,
        description: product.description,
      });
    });
  }

  render() {
    return (
...
  <button
                    className="btn btn-outline-dark flex-shrink-0"
                    type="button"
                    style={{ marginLeft: "10px" }}
                    onClick={() =>
                      this.props.onAddToCart(
                        this.state.id,
                        this.state.name,
                        this.state.description,
                        this.state.price
                      )
                    }
                  >
                    <i className="bi-cart-fill me-1"></i>
                    Add to cart
                  </button>
...

今天早些时候我遇到了类似的问题。我的 localStorage 在刷新时被重写,尽管 localStorage 通常用于在刷新/浏览器关闭之间传输数据。

我意识到的问题是我将 localStorage 设置为渲染时的状态,而我的状态被初始化为空值。看起来您只在代码中调用 localStorage.setItem() 一次,并将其设置为状态。问题是当 localStorage.setItem() 被调用时,你的状态是 仍然是一个空数组 .

React 的this.setState() 方法是一个异步方法,意味着它将被添加到一个堆栈中运行。它不承诺何时开始 运行 或何时结束。看起来你在调用 localStorage.setItem() 之前调用了 this.setState(),这意味着它没有在你更改 localStorage.

之前及时更新状态

我建议将对 localStorage 的调用放在 this.setState() 的第二个参数回调函数中。这个回调函数是总是运行状态设置后

您的状态 setter 将如下所示:

      this.setState(
        {
          cart: [...this.state.cart, holder],
        },
        () => {
          console.log("Updated Cart: ", this.state.cart);
          localStorage.setItem("cart", JSON.stringify(this.state.cart));
        }
      );

问题是一个逻辑错误。重新加载时,状态(购物车)变为空。但是,在尝试将新商品添加到购物车之前,我从未将状态设置为本地存储中已有的商品。 我添加功能的方式涉及获取当前状态并附加新项目,然后设置本地存储。这意味着如果状态为空,则尝试以这种方式添加新商品只会导致购物车中只有新商品。

我把这一段加到App.js解决了错误

componentDidMount() {
    const sCart = localStorage.getItem("cart");
    const parsedCart = JSON.parse(sCart);

    if (sCart == null) {
      this.setState({ cart: [] });
    } else {
      console.log("cart String mount on shopping cart: ", sCart);
      console.log("cart Object at mount on shopping cart: ", parsedCart);
      this.setState(
        {
          cart: parsedCart,
        }
      );
    }
  }