Josh Winters
Josh Winters

Reputation: 855

Retrieve data from array.map via onClick in react

So i have an array.map of buttons that cycles through an array of api data. When i click this button, I want to take that specific buttons data, and store it in local storage. I am at a loss on how to do this via the googles. Any ideas?

{this.state.sb_headers.map((header, index) => (
    <Link key={index} to={header.title} className="list-group-item list-group-item-action" aria- 
    current="true" onClick={this.storeUrl}>
        <span className='icon-text'>{header.title}</span>
    </Link>
))}

So in the storeUrl function, I want to take the data from the link that was clicked and store it. As an example, lets say there are 5 items in the array that are being looped through. each one has a different URL. I want the URL that i click on.

Upvotes: 0

Views: 838

Answers (2)

Brandon Tiqui
Brandon Tiqui

Reputation: 1439

Let's assume that each header item that you are mapping over has a property named "url".

Your onClick for the Link component would call the storeUrl method with the url parameter:

onClick={this.storeUrl(header.url)}

Then, your storeUrl method would look like this:

storeUrl(url) {
  return function() {
    // do something with url
  }
}

This is a closure and the returned function won't be invoked until the link is clicked.

Upvotes: 1

Spidy
Spidy

Reputation: 40002

The easiest solution (though not the most performant) is assigning a wrapped function to the event listener.

{this.state.sb_headers.map((header, index) => (
    <Link key={index} to={header.title} className="list-group-item list-group-item-action" aria- 
    current="true" onClick={() => this.storeUrl(header)}>
        <span className='icon-text'>{header.title}</span>
    </Link>
))}

You can see I created a fat arrow function that invoked storeUrl with header as the parameter. This creates a new function for every Link on every render. Not optimal but it'll do the trick. Another way to write this is as a function that returns a function:

function storeUrl(header) {
  return function(e) {
    // This is the function that's called on click, it has access
    // to header via lexical scope
  }
}

{this.state.sb_headers.map((header, index) => (
    <Link key={index} to={header.title} className="list-group-item list-group-item-action" aria- 
    current="true" onClick={this.storeUrl(header)}>
        <span className='icon-text'>{header.title}</span>
    </Link>
))}

The final option is to attach some data to the button that can be retrieved through the click event.

{this.state.sb_headers.map((header, index) => (
    <Link key={index} to={header.title} className="list-group-item list-group-item-action" aria- 
    current="true" onClick={this.storeUrl} data-index={index}>
        <span className='icon-text'>{header.title}</span>
    </Link>
))}

// Your storeUrl method will receive e as an event
function storeUrl(e) {
  // Get more information about the click
  // The value will be a string so the + transforms it back to a number
  let index = +e.target.getAttribute('data-index');
  let header = this.state.sb_headers[index];

  // Whatever you were going to do with header
}

This solution is more performant as it doesn't create a bunch of extra wrapped functions, though the performance is can be negligible depending on the application size.

Upvotes: 2

Related Questions