Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React js onClick can't pass value to method

I want to read the onClick event value properties. But when I click on it, I see something like this on the console:

SyntheticMouseEvent {dispatchConfig: Object, dispatchMarker: ".1.1.0.2.0.0:1", nativeEvent: MouseEvent, type: "click", target 

My code is working correctly. When I run I can see {column} but can't get it in the onClick event.

My Code:

var HeaderRows = React.createClass({   handleSort:  function(value) {     console.log(value);   },   render: function () {     var that = this;     return(       <tr>         {this.props.defaultColumns.map(function (column) {           return (             <th value={column} onClick={that.handleSort} >{column}</th>           );         })}         {this.props.externalColumns.map(function (column) {           // Multi dimension array - 0 is column name           var externalColumnName = column[0];           return ( <th>{externalColumnName}</th>);         })}       </tr>     );   } }); 

How can I pass a value to the onClick event in React js?

like image 678
user1924375 Avatar asked Apr 22 '15 23:04

user1924375


People also ask

How do you pass a value on onClick React?

To pass an event and parameter onClick in React:Pass an inline function to the onClick prop of the element. The function should take the event object and call handleClick . Pass the event and parameter to handleClick .

How do you pass a parameter in React?

In order to pass a value as a parameter through the onClick handler we pass in an arrow function which returns a call to the sayHello function. In our example, that argument is a string: 'James': ... return ( <button onClick={() => sayHello('James')}>Greet</button> ); ...

How do you pass parameters to an event handler React?

Passing the event object of react as the second argument. If you want to pass a parameter to the click event handler you need to make use of the arrow function or bind the function. If you pass the argument directly the onClick function would be called automatically even before pressing the button.


2 Answers

Easy Way

Use an arrow function:

return (   <th value={column} onClick={() => this.handleSort(column)}>{column}</th> ); 

This will create a new function that calls handleSort with the right params.

Better Way

Extract it into a sub-component. The problem with using an arrow function in the render call is it will create a new function every time, which ends up causing unneeded re-renders.

If you create a sub-component, you can pass handler and use props as the arguments, which will then re-render only when the props change (because the handler reference now never changes):

Sub-component

class TableHeader extends Component {   handleClick = () => {     this.props.onHeaderClick(this.props.value);   }    render() {     return (       <th onClick={this.handleClick}>         {this.props.column}       </th>     );   } } 

Main component

{this.props.defaultColumns.map((column) => (   <TableHeader     value={column}     onHeaderClick={this.handleSort}   /> ))} 

Old Easy Way (ES5)

Use .bind to pass the parameter you want, this way you are binding the function with the Component context :

return (   <th value={column} onClick={this.handleSort.bind(this, column)}>{column}</th> ); 
like image 153
Austin Greco Avatar answered Sep 21 '22 03:09

Austin Greco


There are nice answers here, and i agree with @Austin Greco (the second option with separate components)
There is another way i like, currying.
What you can do is create a function that accept a parameter (your parameter) and returns another function that accepts another parameter (the click event in this case). then you are free to do with it what ever you want.

ES5:

handleChange(param) { // param is the argument you passed to the function     return function (e) { // e is the event object that returned      }; } 

ES6:

handleChange = param => e => {     // param is the argument you passed to the function     // e is the event object that returned }; 

And you will use it this way:

<input      type="text"      onChange={this.handleChange(someParam)}  /> 

Here is a full example of such usage:

const someArr = ["A", "B", "C", "D"];    class App extends React.Component {    state = {      valueA: "",      valueB: "some initial value",      valueC: "",      valueD: "blah blah"    };      handleChange = param => e => {      const nextValue = e.target.value;      this.setState({ ["value" + param]: nextValue });    };      render() {      return (        <div>          {someArr.map(obj => {            return (              <div>                <label>                  {`input ${obj}   `}                </label>                <input                  type="text"                  value={this.state["value" + obj]}                  onChange={this.handleChange(obj)}                />                <br />                <br />              </div>            );          })}        </div>      );    }  }    const rootElement = document.getElementById("root");  ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>  <div id="root"></div>

Note that this approach doesn't solve the creation of a new instance on each render.
I like this approach over the other inline handlers as this one is more concise and readable in my opinion.

Edit:
As suggested in the comments below, you can cache / memoize the result of the function.

Here is a naive implementation:

let memo = {};    const someArr = ["A", "B", "C", "D"];    class App extends React.Component {    state = {      valueA: "",      valueB: "some initial value",      valueC: "",      valueD: "blah blah"    };      handleChange = param => {      const handler = e => {        const nextValue = e.target.value;        this.setState({ ["value" + param]: nextValue });      }      if (!memo[param]) {        memo[param] = e => handler(e)      }      return memo[param]    };      render() {      return (        <div>          {someArr.map(obj => {            return (              <div key={obj}>                <label>                  {`input ${obj}   `}                </label>                <input                  type="text"                  value={this.state["value" + obj]}                  onChange={this.handleChange(obj)}                />                <br />                <br />              </div>            );          })}        </div>      );    }  }    const rootElement = document.getElementById("root");  ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>  <div id="root" />
like image 21
Sagiv b.g Avatar answered Sep 20 '22 03:09

Sagiv b.g