2

I can’t increase the quantity in a nested array in any way, I have already tried many ways. I've tried spread, but it doesn't work. I need quantity to increase for a specific id. Please, instead of criticism, please write how to solve and what I'm doing wrong. I will be grateful for help. Updated with suggestions

App.js

import React, { Component } from "react";
import ClickId from "./ClickId";
import Cart from "./Cart";
import { BrowserRouter, Route, Routes } from "react-router-dom";

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      products: [
        {
          id: "Adidas"
        },
        {
          id: "Puma"
        },
        {
          id: "Nike"
        }
      ],
      countId: {
        quantityId: []
      }
    };
  }
  IncrementItem = (id) => {
    this.setState((prevState) => {
      let newState = JSON.parse(JSON.stringify(prevState)); // deep copy
      let products = this.state.products.map((p) => p.id);
      for (let i = 0; i < newState.countId.quantityId.length; i++) {
        if (newState.countId.quantityId[i].id === products) {
          newState.countId.quantityId[i].quantity += 1;
        }
      }
      return newState;
    });
  };
  DecrementItem = (id) => {
    this.setState((prevState) => {
      let newState = JSON.parse(JSON.stringify(prevState)); // deep copy
      for (let i = 0; i < newState.countId.quantityId.length; i++) {
        if (newState.countId.quantityId[i].id === this.state.products.id) {
          newState.countId.quantityId[i].quantity -= 1;
        }
      }
      return newState;
    });
  };
  CountId = (event) => {
    this.setState({
      countId: {
        ...this.state.countId,
        quantityId: this.state.countId.quantityId.concat({
          id: event.currentTarget.id,
          quantity: 1
        })
      }
    });
  };
  render() {
    return (
      <div>
        <BrowserRouter>
          <Routes>
            <Route
              path="/ClickId"
              element={
                <ClickId CountId={this.CountId} countId={this.state.countId} />
              }
            />
            <Route
              path="/Cart"
              element={<Cart IncrementItem={this.IncrementItem} />}
            />
          </Routes>{" "}
        </BrowserRouter>{" "}
      </div>
    );
  }
}

ClickId.js

import React, { Component } from "react";

export default class ClickId extends Component {
  constructor(props) {
    super(props);
    this.state = {
      products: [
        {
          id: "Adidas"
        },
        {
          id: "Puma"
        },
        {
          id: "Nike"
        }
      ]
    };
  }
  countId = () => {
    if (this.props.CountId) {
      this.props.CountId();
    }
  };
  render() {
    return (
      <div>
        {this.state.products.map((p) => {
          return (
            <div id={p.id} onClick={this.props.clickId}>
              ClickId
            </div>
          );
        })}
      </div>
    );
  }
}

Cart.js

import React, { Component } from "react";

export default class Cart extends Component {
  constructor(props) {
    super(props);
    this.state = {
      products: [
        {
          id: "Adidas"
        },
        {
          id: "Puma"
        },
        {
          id: "Nike"
        }
      ]
    };
  }
  render() {
    return (
      <div>
        {this.state.products.map((p) => {
          return (
            <div>
              <button onClick={() => this.props.IncrementItem(p.id)}>
                +
              </button>
              <div className='s.count'>
                {JSON.stringify(
                  value.state.countId.quantityId.map((i) => i.quantity)
                )}
              </div>
              <button onClick={() => this.props.DecrementItem(p.id)}>
                -
              </button>
            </div>
          );
        })}
      </div>
    );
  }
}
Ivan Reshetnikov
  • 398
  • 2
  • 12
Nord
  • 55
  • 6
  • Please make the code syntactically correct – Ivan Reshetnikov Jun 12 '22 at 14:59
  • Pay attention that "products" are just strings and don't have `id`. So, `p.id` is always undefined here `this.state.products.find(p => p.id === i.id` – Ivan Reshetnikov Jun 12 '22 at 15:10
  • @IvanReshetnikov I'm sorry, I added an identifier to products, I didn't add it by mistake – Nord Jun 12 '22 at 15:30
  • @IvanReshetnikov I wrote under your answer – Nord Jun 13 '22 at 16:03
  • @IvanReshetnikov I'm trying to apply your solution but it doesn't work. The answer in quantity comes to me in the form of [1] and is not updated. Can you please write a working code and write an explanation for me to study it. I'll count the answer for you. products is all the products that are on the site, and countId.quantityId is information about the clicked product – Nord Jun 14 '22 at 10:49
  • I have no idea about data in `props`. Please provide more context. It would be perfect if you present it as `` – Ivan Reshetnikov Jun 14 '22 at 11:16
  • @IvanReshetnikov In products.id I initially have products. The countId.quantityId contains data about the click in particular (id and quantity). I create a collection with this code: CountId = (event) => { this.setState({ countId:{ ...this.state.countId, quantityId: this.state.countId.quantityId.concat({id:(event.currentTarget.id), quantity: 1})}}) I take the id of the product that is added to the cart and add quantity to it and this is how I create an object in countId.quantityId – Nord Jun 14 '22 at 11:26
  • @IvanReshetnikov Please check my changes. Code at that level of the test, taking into account your suggestions – Nord Jun 14 '22 at 15:45
  • thank you for extra details. I submitted an edit: formatted the code and added imports to make the code executable. Where did `value` come from in `Cart.js`? – Ivan Reshetnikov Jun 14 '22 at 16:22
  • @IvanReshetnikov Didn't understand you: "Where did value come from in Cart.js?" If you mean why I'm using Cart.js, it's the ultimate beneficiary of countId.quantityId.quantity – Nord Jun 14 '22 at 17:04
  • `value.state.countId.quantityId.map((i) => i.quantity)`. `value` is undefined in the `Cart` – Ivan Reshetnikov Jun 14 '22 at 17:51
  • I'm leaving the discussion. I don't have much time. Thank you for clarifications – Ivan Reshetnikov Jun 14 '22 at 17:56
  • @IvanReshetnikov value.state.countId.quantityId.map((i) => i.quantity). value is undefined in the Cart i am passing data through context instead of passing through props – Nord Jun 14 '22 at 18:27
  • @IvanReshetnikov Can you help me figure it out? – Nord Jun 14 '22 at 18:28
  • 1
    I researched a question with JSON and read an interesting answer to a question on stackoverflow and decided to use lodash for deep copying (I had a problem with deep copying) https://stackoverflow.com/questions/48710797/how-do-i-deep-clone-an-object-in-react – Nord Jun 15 '22 at 08:49

1 Answers1

0

You return { quantitiy: "{{updated value}}" } from setState.

However, setState's callback should return the same structure as this.state has (some fields of the first level can be omitted).

In your case it can look like

this.setState(prevState => {
  var newState = JSON.parse(JSON.stringify(prevState)) // deep copy
  newState.countId.quantityId[0].quantity = "{{updated value}}"
  return newState
})

Example

import React, { Component } from "react";

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      products: [
        { id: 1, name: "Adidas", quantity: 1 },
        { id: 2, name: "Puma", quantity: 1 }
      ]
    };
  }
  IncrementItem = (id) => {
    this.setState((prevState) => {
      var newState = JSON.parse(JSON.stringify(prevState)); // deep copy
      for (let i = 0; i < newState.products.length; i++) {
        if (newState.products[i].id === id) {
          newState.products[i].quantity += 1;
        }
      }
      return newState;
    });
  };
  render() {
    return (
      <div>
        {this.state.products.map((product) => {
          return (
            <button onClick={() => this.IncrementItem(product.id)}>
              {product.name} +
            </button>
          );
        })}
        <div>{JSON.stringify(this.state)}</div>
      </div>
    );
  }
}
Ivan Reshetnikov
  • 398
  • 2
  • 12
  • I'm a little confused with your answer. Could you explain in more detail. Thanks – Nord Jun 12 '22 at 15:35
  • @Nord, `newState` has the same structure with `this.state`. In your code the returned object has `quantity` key, which is absent in `this.state` – Ivan Reshetnikov Jun 12 '22 at 16:10
  • Hello, sorry for the long reply. I just got to see your reply. In your example, the error is in state. Products are the objects I get from Graphql and countId is the product click data. – Nord Jun 13 '22 at 16:02
  • @Nord, I've used another state on purpose. It's a working example with state updating. You can adapt it for your case. Key idea is that `setState` must return an object, which has properties/fields from `this.state` – Ivan Reshetnikov Jun 13 '22 at 16:14
  • 1
    Uncaught (in promise) Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops. – Nord Jun 13 '22 at 16:58