0

I'm getting this error -
Cannot add property Quantity, object is not extensible in Files.jsx

itemsInCart array of objects is defined at the App.jsx and getting filled in other jsx component, I checked with console.

App.jsx

const ItemsCartWithLocalStorage = (userItems) => {
  const itemsInCart = useRef(
    JSON.parse(localStorage.getItem(userItems)) || new Array());
 

  useEffect(() => {
    console.log('localStorage setItem');
    localStorage.setItem(userItems, JSON.stringify(itemsInCart));
  }, [itemsInCart]);

  return [itemsInCart];

};
function App() {

const itemsInCart = useRef(ItemsCartWithLocalStorage('itemsQuantityString'));
return (
      <Files itemsInCart={itemsInCart} />
    )
   }

Files.jsx

const Files= ({ itemsInCart }) => {

 const array = [...itemsInCart.current]; 
 for (let i = 0; i < array.length; i++) {
 array[i]['Quantity'] = 1;  "TypeError: Cannot add property Quantity, object is not extensible"

How can I fix this error ?

skyboyer
  • 22,209
  • 7
  • 57
  • 64
ExtraSun
  • 528
  • 2
  • 11
  • 31
  • What is the structure of array? – Sinan Yaman Aug 09 '21 at 12:41
  • Are you sure that `array[i]` is an object – Rahul Aug 09 '21 at 12:42
  • @SinanYaman you meant properties ? `[{CategoryName: "" Price: 26 ProductDescription: "" ProductID: 2 ProductImage: "" ProductName: "" ProductOverview: "" Stock: 290},{...}]` – ExtraSun Aug 09 '21 at 12:44
  • @Rahul when `itemsInCart` was a state it worked really well, but I didn't want re-render so I made it `useRef` to array. – ExtraSun Aug 09 '21 at 12:45
  • You don't have a `Quantity` field in the object. And since it is type-safe, it tells you that you can't add extra fields to the object. Therefore, you can't add quantity. Try changing price in the same line, and it will work. – Sinan Yaman Aug 09 '21 at 12:47
  • Why are you using `ref` to prevent re renders, use `useMemo` or split the component b/w dynamic and static component. Other solution: save data into `localStorage/sessionStorage` – Rahul Aug 09 '21 at 12:48
  • You must have set [`Object.preventExtensions()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/preventExtensions) or any library you using did the same for you. – Shivam Sharma Aug 09 '21 at 12:51
  • @Rahul I tried to call it `const numberOfItems = useMemo(() => {` but where shall I call it when `itemsInCart ` changed ? – ExtraSun Aug 09 '21 at 12:57
  • @ExtraSun first learn `useMemo` and what it does. You need to wrap the component not normal data. When you'll wrap your component with `useMemo` then you can decide that when you want to rerender the component. – Rahul Aug 09 '21 at 13:01
  • @Rahul you probably mixed with `memo` hook that wrapping the component – ExtraSun Aug 09 '21 at 13:03
  • @ExtraSun i used to use `useMemo` to solve such kind of question. – Rahul Aug 09 '21 at 13:05
  • 1
    Does this answer your question? [useRef.currrent - how to fix "Cannot read property 'current' of undefined, and more issues](https://stackoverflow.com/questions/68711409/useref-currrent-how-to-fix-cannot-read-property-current-of-undefined-and-m) – Martin Aug 09 '21 at 13:11
  • @Rahul I tried again with useMemo but its doesnt go checked - `const numberofItems = useMemo(() => { console.log('numberofItems useMemo'); }, [itemsInCart?.current]);` no console nothing - `return (
    `
    – ExtraSun Aug 09 '21 at 13:12
  • Why are you getting `itemsInCart.current` in `array` and updating , shouldn't you use `itemsInCart.current[0].current` as you are using `useRef` nested twice? – Shivam Sharma Aug 09 '21 at 14:10
  • @ShivamSharma why `current[0].current` twice ? I didn't understand the *nested twice* part. – ExtraSun Aug 09 '21 at 14:12
  • I have created [a sandbox](https://codesandbox.io/s/hardcore-frost-81yso?file=/src/App.js) similar to your code, check the console. – Shivam Sharma Aug 09 '21 at 14:15
  • @ShivamSharma Sorry for my ignorance but I didn't see anywhere by googling and React docs the `current[0].current` explanation. Where can I find an explanation about it ? Thank for the effort still getting `TypeError: itemsInCart.current[0].current is not iterable ` – ExtraSun Aug 09 '21 at 14:19
  • @ExtraSun `itemsInCart.current[0].current` is an `object` so you can not iterate over it. – Rahul Aug 09 '21 at 14:24
  • @ExtraSun try `console.log(typeof itemsInCart.current[0].current)` you'll get the result – Rahul Aug 09 '21 at 14:24
  • It doesn't require explanation, as in my example, In `Wrap`, `data.current = Array of 2 objects`, returned `[data] = Array with 1 element which is an Object having "current" set to Array of 2 objects`, Inside App, `useRef` is calling `Wrap` so `data.current` becomes `[data] = Array with 1 element which is an Object having "current" set to Array of 2 objects`, Now inside `Ele`, to access the main data, you will first get `dat.current` which is Array of 1 obj, then `data.current[0]` means that obj, then `data.current[0].current` means the exact data (Array of 2 objects). – Shivam Sharma Aug 09 '21 at 14:27
  • If it's not iterable then you just need to log it and see what does it actually contains, it'll not be an Object or Array, so you can't add a key `"Quantity"` to it. It must be an immutable Object, I have updated my answer for the same. – Shivam Sharma Aug 09 '21 at 14:29
  • @ShivamSharma I still can't understad how in your codesandbox the `[...data.current[0].current]` gives the whole array with two object, and in my code `const array = [...itemsInCart.current[0].current] gives an error. – ExtraSun Aug 09 '21 at 14:44
  • @ExtraSun, Just `console.log` the value of `data.current` and you will get the answer, You might be storing a string in localstorage that is two times JSON stringified. – Shivam Sharma Aug 09 '21 at 14:47
  • See if [this relates](https://stackoverflow.com/questions/45798885/object-is-not-extensible-error-when-creating-new-attribute-for-array-of-objects) with your problem. – Shivam Sharma Aug 09 '21 at 14:49
  • @ShivamSharma Did you mean here - `localStorage.setItem(userItems, JSON.stringify(itemsInCart))` ? Without the `stringify` there is an error. Can we continue in a chat ? – ExtraSun Aug 09 '21 at 14:55
  • @ShivamSharma `localStorage` takes only strings not objects thats why is has to be with `JSON.stringify` and `JSON.parse` – ExtraSun Aug 09 '21 at 14:57
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/235793/discussion-between-shivam-sharma-and-extrasun). – Shivam Sharma Aug 09 '21 at 15:05

1 Answers1

0

You must have set Object.preventExtensions() or any library you use is doing the same for you. After this call, you can't add new properties to the object passed as an argument in the call, and in your case, you might be adding the "Quantity" field and it was not in the origin object.

The Object.preventExtensions() method prevents new properties from ever being added to an object (i.e. prevents future extensions to the object). Source

The JavaScript exception "can't define property "x": "obj" is not extensible" occurs when Object.preventExtensions() marked an object as no longer extensible, so that it will never have properties beyond the ones it had at the time it was marked as non-extensible. Source

In strict mode, attempting to add new properties to a non-extensible object throws a TypeError. In sloppy mode, the addition of the "x" property is silently ignored. Source

Below is the code for replicating the same.

'use strict';

const itemsInCart = {current:[{a:"a"},{a:"b"}]};
Object.preventExtensions(itemsInCart.current[1]);
const array = [...itemsInCart.current];
array[1]["q"] = 1
console.log(itemsInCart.current)

Or you might be trying to update an immutable object like String by adding the key Quantity. It's not possible in strict mode and we get TypeError while in Sloppy mode it's just ignored.

'use strict';

const str = "abc";

str["Quantity"] = 1;
Shivam Sharma
  • 1,277
  • 15
  • 31
  • Not correct, when `itemsInCart` was a `state` it worked and "Quantity" was added to the array object. – ExtraSun Aug 09 '21 at 13:16
  • I am not sure about React may be the hooks like `useRef` are the culprit. Or as [prop are read-only](https://reactjs.org/docs/components-and-props.html#props-are-read-only) so they might be having this `preventExtensions` set behind the scenes. – Shivam Sharma Aug 09 '21 at 13:22
  • `TypeError: Cannot add property q, object is not extensible` the same error with your code. – ExtraSun Aug 09 '21 at 13:23
  • Yes, I was showing you that when this error occurs as you asked in the question "Why am I seeing this error?" – Shivam Sharma Aug 09 '21 at 13:28
  • how to access nonextensible obj[k] dynamically via var k ? – droid192 Dec 13 '22 at 16:12