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?
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 .
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> ); ...
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.
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.
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> );
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" />
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With