I am experiencing a very frustrating issue with regards to object destructuring in my function parameters. I have the following code in one of my components:
import React from "react";
import { range } from "../../utils";
import { checkGuess } from "../../game-helpers";
function Guess({ guess, answer }) {
const guessEmpty = guess === undefined ? true : false;
const letters = !guessEmpty && checkGuess(guess.value, answer);
function renderLetter({ letter = undefined, status = undefined } = {}, num) {
return (
<span className={`cell ${status}`} key={num}>
{letter}
</span>
);
}
return (
<>
{
<p className="guess">
{range(5).map((num) => renderLetter(letters[num], num))}
</p>
}
</>
);
}
export default Guess;
The letters
constant is an array, which will either be set to false
or consist of a list of objects depending on whether the guess
input parameter for the Guess
function is empty or not.
When I pass letters[num]
(which can be an object, or undefined) into my renderLetter
function, my letter
and status
input parameters are either converted to undefined or strings depending on the input through object destructuring. This all works great.
However, instead of rendering the <span>
elements by using the renderLetter
function, I now want to move this to a new component. The code for this component is:
import React from "react";
function Letter({ letter = undefined, status = undefined } = {}) {
return (
<>
<span className={`cell ${status}`}>{letter}</span>
</>
);
}
export default Letter;
Similarly to the way I called the renderLetter
function, I am now attempting to render the components:
return (
<>
{
<p className="guess">
{range(5).map((num) => (
<Letter letter={letters[num]} num={num} />
))}
</p>
}
</>
);
}
However, when logging letter
and status
parameters inside the Letter
component, the letter
parameter returns an object, and the status
parameter returns undefined. As such, I’m assuming I’m messing up in destructuring the input correctly.
I fail to see why however, since doing it this exact same way does work when using a function inside the same component, while it does not when transferring the code to a separate component.
Any help in figuring this out would be greatly appreciated!
3
Answers
You’re very close. When you converted the
renderLetter
function into a full component, you forgot the first parameter of a React component is always the props object. Since you’re now passingletters[num]
as a prop instead of an argument, it will arrive in the props object under theletter
key.Your destructuring needs to account for this in your component:
You need to access the
letter
prop first from the props object. When you use a component like this:React will call your
Letter
function, passing it in an object roughly of this shape as the first argument toLetter
:Mentally, you can think of React as calling your function as
Letter({letter: letters[num], num: num});
, but do be aware that this isn’t exactly how React calls your component under the hood (it does some other things such as binding thethis
, and passing in additional arguments and props).That means in your functional component, to access the object
letters[num]
you need to access it via theletters
property. Without destructuring the function arguments, this would look like:With destructuring the arguments, you’d need to do nested destructuring:
The way your
Letter
component is defined, it takes two props:letter
andstatus
, both expected to be strings or undefined.But
<Letter letter={letters[num]} num={num} />
does pass an object to theletter
prop, nothing to thestatus
prop, and a number to the non-existing (and therefore ignored)num
prop. What you want instead isor simpler