I am trying to return the key of the item selected within a mapped list of data.
I have included the code from the individual card below. I am using this card to map an unknown number of items within a array in a high component.
Currently the key is return undefined but the event is being logged correctly.
I need to isolate the key that has been selected as this will be used in a further request.
Where am I going wrong. Any help would be greatly appreciated.
const PreGameCard = (props) => {
const day = new Date(props.Date).getDate()
const monthString = date.toLocaleString('en-US',{month: 'long'})
const year = new Date(props.Date).getFullYear()
const handleClick = (event,key) =>{
console.log(key)
console.log(event)
}
return (
<>
<li className='menulist' key={props.key} value={props.key} onClick={(e)=>handleClick(e,props.key)}>
<div className='CardContainer'>
<div className='CardHeader'>{props.Name}</div>
<div className='Day'>{day}</div>
<div className='Month'>{monthString}</div>
<div className='Year'>{year}</div>
<div className='Ticker'>{props.Ticker}</div>
<div className='Asset'>{props.Asset}</div>
</div>
</li>
</>
);
};
export default PreGameCard
parent component
import react from 'react'
import "./PreGameMenu.css"
import PreGameCard from './PreGameCard';
const PreGameMenu = (props) => {
const PreGameItems = props.data
return (
<div className='Menu'>
{PreGameItems.map(item => <PreGameCard
key={item.key}
Name={item.Name}
Date={item.Date}
Asset={item.Asset}
Ticker={item.Ticker}
></PreGameCard>)}
</div>
);
};
export default PreGameMenu
CodePudding user response:
When you do this:
<PreGameCard key={"something"} ... />
...the key is not included in the props of the component; it's used directly by React instead. As a result, props.key
will always be undefined
. If you need the value of the key within the component, you'll have to pass it separately as a different prop (in addition to using it as key
if the PreGameCard
elements are in an array). From the keys documentation on the react website) (my emphasis):
Keys serve as a hint to React but they don’t get passed to your components. If you need the same value in your component, pass it explicitly as a prop with a different name:
const content = posts.map((post) => <Post key={post.id} id={post.id} title={post.title} /> ); With the example above, the Post component can read `props.id`, but not `props.key`.
Some other notes:
- You don't need to create a wrapper around your event handler to pass the key around, you already have
props
available in your event handler. value
is not a valid property forli
elements.- There's no reason to wrap your
li
in a fragment. - There's no reason to put a
key
prop on theli
. It's not in an array. (YourPreGameCard
elements may be, but not theli
elements.) - Where you have
key={key}
in your code,key
is an undeclared identifier. (You probably meantkey={props.key}
, but again note that you can't accessprops.key
.) - The overwhelming convention in JSX code is that props start with lower-case letters (so
date
rather thanDate
, etc.). - When you have a JSX element with no content, it's best to use
/>
on the start tag to close it rather than using></CompName>
. (And that's valid even where it wouldn't be in HTML.)
Here's an updated example passing the key as an id
property and addressing the other points:
const PreGameMenu = (props) => {
const preGameItems = props.data;
return (
<div className="Menu">
{preGameItems.map((item) => (
<PreGameCard
key={item.key}
id={item.key}
name={item.Name}
date={item.Date}
asset={item.Asset}
ticker={item.Ticker}
/>
))}
</div>
);
};
const PreGameCard = (props) => {
const { id, date } = props;
const day = new Date(date).getDate();
const monthString = date.toLocaleString("en-US", { month: "long" });
const year = new Date(date).getFullYear();
const handleClick = (event) => {
console.log(id); // *** The handler closes over this, no need to pass it in
};
return (
<li className="menulist" onClick={handleClick}>
<div className="CardContainer">
<div className="CardHeader">{props.name}</div>
<div className="Day">{day}</div>
<div className="Month">{monthString}</div>
<div className="Year">{year}</div>
<div className="Ticker">{props.ticker}</div>
<div className="Asset">{props.asset}</div>
</div>
</li>
);
};
const data = [
{
key: 1,
Name: "one",
Date: new Date(2022, 6, 1),
Asset: "asset1",
Ticker: "ticker1",
},
{
key: 2,
Name: "two",
Date: new Date(2022, 6, 2),
Asset: "asset2",
Ticker: "ticker2",
},
{
key: 3,
Name: "three",
Date: new Date(2022, 6, 3),
Asset: "asset3",
Ticker: "ticker3",
},
];
const Example = () => {
return <ul><PreGameMenu data={data} /></ul>;
};
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Example />);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>