Home > front end >  How to return key from mapped list via onclick function in react js
How to return key from mapped list via onclick function in react js

Time:08-01

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 for li elements.
  • There's no reason to wrap your li in a fragment.
  • There's no reason to put a key prop on the li. It's not in an array. (Your PreGameCard elements may be, but not the li elements.)
  • Where you have key={key} in your code, key is an undeclared identifier. (You probably meant key={props.key}, but again note that you can't access props.key.)
  • The overwhelming convention in JSX code is that props start with lower-case letters (so date rather than Date, 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>

  • Related