Home > Software engineering >  Objects getting the same ID
Objects getting the same ID

Time:08-02

I'm pulling data from a GraphQL backend. Here is the data that I'm pulling.

{
  "data": {
    "product": {
      "attributes": [
        {
          "id": "Capacity",
          "items": [
            {
              "id": "256GB",
              "displayValue": "256GB"
            },
            {
              "id": "512GB",
              "displayValue": "512GB"
            }
          ]
        },
        {
          "id": "With USB 3 ports",
          "items": [
            {
              "id": "Yes",
              "displayValue": "Yes"
            },
            {
              "id": "No",
              "displayValue": "No"
            }
          ]
        },
        {
          "id": "Touch ID in keyboard",
          "items": [
            {
              "id": "Yes",
              "displayValue": "Yes"
            },
            {
              "id": "No",
              "displayValue": "No"
            }
          ]
        }
      ]
    }
  }
}

I'm then iterating through the attributes array and giving unique IDs, _id to differentiate the different items. It turns out that the item that has an ID With USB 3 ports and Touch ID in keyboard always get the same ID. I'm using nanoid.

Here is the code

import { PureComponent } from "react";
import { useParams } from 'react-router-dom';
import { Query } from '@apollo/client/react/components';
import GET_PRODUCT from "../../graphql/getProduct";
import { nanoid } from 'nanoid';
import ProductDetailComponent from "./ProductDetailComponent";
import './ProductDetail.css'


class ProductDetail extends PureComponent {
  render() {
    const { id } = this.props.params;
    const { currency, addToCart, closeCurrencyOverlay } = this.props;
    return (
      <Query
        key="yes"
        query={GET_PRODUCT}
        variables={{ id }}
        fetchPolicy="network-only"
      >
        {({ loading, data}) => {
          if (loading) return null;
          let newAttributes = [];
          data.product.attributes.map((attribute) => {
            attribute.items.map((item) => {
              item._id = nanoid(); // <-- Giving the id from here
            })
            newAttributes.push(attribute)
          })
          const newData = { ...data, attributes: newAttributes }
          return <ProductDetailComponent data={newData} currency={currency} addToCart={addToCart} closeCurrencyOverlay={closeCurrencyOverlay} id={id}/>
        }}
      </Query>
    )
  }

}

export default (props) => (
  <ProductDetail
    {...props}
    params={useParams()}
  />
);

I'm just wondering why they always get the same ID.

Here is a screenshot of the Chrome dev tools Dev tools

CodePudding user response:

If you are always getting the same id for the elements inside the items array and looking at your code where you assign item._id = nanoid(); it makes me think that those objects share the same reference.

Here is a quick example to illustrate why this would happen:

// reference of array values
const yesNoArr = [
  { id: 1, text: 'Yes' }, 
  { id: 2, text: 'No' }
];

const objs = [
  // here both objects share the same reference of "items" property:
  { items: yesNoArr, text: 'with USB 3 ports' },
  { items: yesNoArr, text: 'Touch Id in keyboard' }
];

// if at this point you try to set _id to items[0]:

objs[0].items[0]._id = 123; // this will work fine and assign _id = 123
objs[1].items[0]._id = 456; // but this will overwrite previous "123" by "456" because they point to the same object

// result:
console.log(JSON.stringify(objs, null, 2));

If you want to avoid this behavior you'll have to make a modified copy of the items so that they don't point to the same referenced object. Try replacing this piece of code and see how it behaves:

const newAttributes = data.product.attributes.map((attribute) => {
  return {
    ...attribute,
    items: attribute.items.map((item) => {
      // make a copy of each item to get a different reference:
      return {
        ...item,
        _id: nanoid(),
      };
    }),
  };
});

console.log(newAttributes);
  • Related