'useState is initialized multiple times
Let's take some kind of array of objects, for example:
let arrayTemp = [
{type: {id: 1}},
{type: {id: 2}},
{type: {id: 3}},
{type: {id: 4}}
];
Next, we create a component to which we will pass this array as a parameter.
<StubGreat array={arrayTemp}/>
In the component, create a hook and initialize it like this:
const [tag, setTag] = useState(array[0].type.id);
Now let's start deleting the elements in the array one by one. You can remove it using the pop() function. When we remove the last element in the array, we get this error: Uncaught TypeError: Cannot read properties of undefined (reading 'type') at StubGreat (StubGreat.js:14:1)
What the hell is going on? The initialization of the component must occur once, why is the value undefined not set, but an error appears? How can this be fixed?
Solution 1:[1]
What the hell is going on?
You're trying to reference .type on a value that is undefined. According to the description, a parent component controls arrayTemp and passes it to StubGreat as a prop. And every time that prop changes, StubGreat re-renders.
Presumably (commonly) the calls to useState are among the first things a component does. So presumably you have a function component and this is one of the first lines in it:
const [tag, setTag] = useState(array[0].type.id);
When a function component renders, the function itself is called.
Now it's time to step out of React-land for a moment and just think about this purely in terms of JavaScript. Because that's all that's running here. What's happening is a function is being invoked, an empty array is being passed to it, and the first thing the code does with that empty array is try to read a property called type on the first element of that empty array.
Which produces the error observed, because the empty array has no first element.
Regardless of what useState does internally, or how React internally discerns state representations and figures out what may or may not need to be re-calculated or re-rendered, the JavaScript code shown is trying to de-reference an undefined value. Which is an error.
In fact, when the error occurs, useState isn't even being invoked. The value being passed to the function has to be resolved before the function can be invoked with that value. And resolving that value is what produces the error.
There are a variety of approaches you can take, depending on what you're building and how you want it to behave. (None of which we know.) For example, you can supply a default value of some sort:
<StubGreat array={arrayTemp.length > 0 ? arrayTemp : [{type:{}}]}/>
Or you could conditionally de-reference it:
const [tag, setTag] = useState(array.length > 0 ? array[0].type.id : null);
Or you could not render the component at all with an empty array:
{ arrayTemp.length > 0 ? <StubGreat array={arrayTemp}/> : null }
However you want the system to behave in the event of an empty array is up to you. But the one thing you can't do with the empty array is de-reference its first element.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | David |
