OnClick Event binding in React.js - javascript

I would like to pass the parent div id, on click of that div or any child element of the same div. But I am unable to achieve it. Please tell me where I am making a mistake. Code is below:
viewMore: function(i,j){
console.log('You clicked: ', i );
},
render : function(){
var attributeId = "groups_";
attributeId+= index;
return(
//parent div
<div className="groups" id={attributeId} onClick={this.viewMore}>
<div className="floatLeft"> Group Name: <h3>My Name</h3></div>
<span className="floatRight typeCd">POC</span>
<div className="clearfix"> Key Attributes:
<ul>
<li> POC 1</li>
</ul>
</div>
</div>
)
};

viewMore = (i,j) => () => {
console.log(i,j)
}
To pass parameters to event handlers we need to use currying.
With the above method no new functions created all the time while render is called.

Since I see these kind of suggestions in multiple places, I am going to move my comment into an answer as well, to provide an additional view:
class TestComponent extends React.Component {
constructor() {
super();
this.onClick = this.handleClick.bind(this);
}
handleClick(event) {
const {id} = event.target;
console.log(id);
}
render() {
return (
<div>
<h3 id={this.props.id} onClick={this.onClick}>
{this.props.name}
</h3>
</div>
);
}
}
This allows to:
avoid unnecessary binds
access the id and whatever else properties in a much more React-ive manner.
Of course, the above example assumes that you receive the id as a prop, but you can do the necessary manipulations as well.
UPDATE 1 -- Nov 28, 2016
Added link to CodePen from comments above.
UPDATE 2 -- Mar 30, 2017
As mentioned, this wouldn't work if you use React.createClass to define your components. You don't have a constructor to pull this off. You can use other lifecycle methods, if you don't mind a little ugliness.
Having said that, it is 2017. Use ES6, would you?!
UPDATE 3 -- May 12, 2017
If you are using class properties transform, then you can simplify it further:
class TestComponent extends React.Component {
onClick = (event) => {
const {id} = event.target;
console.log(id);
}
render() {
return (
<div>
<h3 id={this.props.id} onClick={this.onClick}>
{this.props.name}
</h3>
</div>
);
}
}
UPDATE 4 -- Feb 4, 2018
Due to improvements of bind and friends in V8 (Chakra and such probably too), you just may be better off using the this.click.bind(this) or wrapping it in an arrow function when passing to onClick.
Why?
The previous method, created for performance reasons only, closed some possibilities for dynamically injecting functions onto the component's prototype.
NOTE 1 -- Apr 14, 2018
Keep in mind that the method mentioned in Update 4 still introduces some performance issues, as on each render pass a new function is created as a result of bind. This, in turn, will trickle down to the child component and cause unnecessary re-renders, as the function changes each time.
The same thing happens when you pass an arrow function inline.
All other methods, like using class properties, will mess with your inheritance (which you should be avoiding, but still), simply due to the fact that, currently, Babel transpiles them to "on-instance" functions, which are not on the prototype chain.
So, this:
class Person {
printA = () => { console.log('a') }
}
becomes:
function _classCallCheck(instance, Constructor) {...abridged...}
var Person = function Person() {
_classCallCheck(this, Person);
this.printA = function () {
console.log('a');
};
};

I've made an updated answer for ES6 here:
https://stackoverflow.com/a/35748912/76840
Essentially, you can use arrow function expressions, which have the benefit of preserving this:
onClick={(event)=>this.viewMore(attributeId, event)}
As of this edit, if you're using Babel with stage-2 enabled, you can use a property like so:
// Within your class...
viewMore = (event) => { /* ... */ }
// Within render method in your JSX
onClick = {this.viewMore}

You can use currying function.
ES5:
viewMore(param) { // param is the argument you passed to the function
return function(e) { // e is the event object that returned
};
}
ES6
viewMore = param => e => {
// param is the argument you passed to the function
// e is the event object that returned
};
And just use it like this:
onClick={this.viewMore("some param")}

Here is an update and an overview of previous answers:
Using onClick={this.viewMore.bind(this, attributeId)} by #HenrikAndersson
.While this approach serves the purpose it uses the bind syntax with which many are not comfortable.
Using public class field mentioned by #ZenMaster.This solution has more or less the same performance, it also comes with a better syntax. But it turns tricky when we have to pass a parameter.
class TestComponent extends React.Component {
onClick = (event) => {
const {id} = event.target;
console.log(id);
}
render() {
return (
<div>
<h3 id={this.props.id} onClick={this.onClick}>
{this.props.name}
</h3>
</div>
);
}
}
The above mentioned approach skips passing parameters and instead uses custom attributes to access the data required in click handler.
A better solution would be :
class MyComponent extends React.Component {
handleClick = (item) => (e) => {
e.preventDefault()
console.log(`This has access to item ${item}! and event(e)`)
}
render(){
const item={ id:'1', value: 'a' }
return(
<button onClick={ this.handleClick(item) } >Click</button>
)
}
}
Reference: Handle events by arrow functions in React app

Here is the code how to use on click event.
var attributeId = "groups_";
attributeId = 32;
const viewMore = (val) => () => {
console.log(val)
}
return (
//parent div
<div className="groups" id={attributeId} onClick={viewMore(attributeId)}>
<div className="floatLeft"> Group Name: <h3>My Name</h3></div>
<span className="floatRight typeCd">POC</span>
<div className="clearfix"> Key Attributes:
<ul>
<li> POC 1</li>
</ul>
</div>
</div>
)

Related

react javascript arrow function without arrows?

I don't understand how this can work in javascript
renderMarkButton(type, icon) {
it looks like an arrow function, but without the arrows. Here's the context:
class HoverMenu extends React.Component {
renderMarkButton(type, icon) {
const { editor } = this.props
return (
<div className="editorButton"
onMouseDown={event => this.onClickMark(event, type)}>
<FontAwesomeIcon color="#666" active={isActive}
className="editorButton" icon={icon} />
</div>
)
}
render() {
return (
<div>
{this.renderMarkButton('bold', {...faBold})}
</div>
)
}
}
I'm also confused by the
const { editor } = this.props
which comes from Slate, I believe. I would have expected this.props to be {type,icon} in this case.
Regarding your questions:
renderMarkButton(type, icon) { is just the es6 class syntax:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
const { editor } = this.props is called "destructuring". You can read about that here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
hope that helps :)
Arrow and bound methods are useful for passing them as callbacks to be called later:
<Component onClick={this.clickHandler}/>
This isn't the case for renderMarkButton because it's called in a place where it's used with correct this context:
this.renderMarkButton('bold', {...faBold})
renderMarkButton is class prototype method. It doesn't work like arrow function because it isn't bound to the context. Calling it with wrong context would result in error because there would be no this.props object:
const unboundFunction = this.renderMarkButton;
unboundFunction('bold', {...faBold});
This is a special syntax according to new class keyword which will let you create classes.
Basically, those are methods of that specific class and you can't define any other method outside of the class using that specific syntax.
For more information, consider MDN as your best partner.

Why twice bind on onClick is required in React?

I have a LandingPageComponent which has a child component DisplayStudent
I have a function deleteStudent in LandingPageComponent. I'm passing this function as a prop to DisplayStudent but I can't understand why I need to bind function deleteStudent in LandingPageComponent and DisplayStudent as well
I need to get id when delete button is clicked see this on jsFiddle
jsfiddle
import React, {
Component
} from 'react';
import DisplayStudent from './DisplayEmployeeComponent'
var data = [{
name: 'student-1',
id: 1
},
{
name: 'student-2',
id: 2
},
{
name: 'student-3',
id: 3
}
];
export default class LandingPage extends Component {
deleteStudent(e) {
console.log('hi', this, e)
}
render() {
return ( <
div >
<
DisplayStudent studentData = {
data
}
deleteStudent = {
this.deleteStudent.bind(this)
} // BINDING FIRST TIME
/> < /
div >
)
}
}
export default function(props) {
return (
props.studentData.map((ele) => {
return ( <
div key = {
ele.id
}
style = {
{
display: 'flex',
padding: '9px 5px 7px 4px'
}
} >
<
div > {
ele.name
} < /div>
<
button onClick = {
props.deleteStudent.bind(this, ele.id)
} // binding second time
>
Delete <
/button> < /
div >
)
})
)
}
Without .bind(this), this inside deleteStudent points to the global object (window), not to your component.
Learn more about bind and this.
You can avoid first bind even second bind in ES6. Here is working example: https://jsfiddle.net/bayucandra/xch1L072/9/
Explanation:
1st bind
deleteStudent = (e) => {
console.log('hi', this, e)
};
This is a new way of how we do bind(this) for ES6 in Babel. Just syntactic sugar to the old way. The old way is by doing bind(this) in the constructor.
2nd bind:
<button
onClick={props.deleteStudent.bind(this, ele.id)}
> Delete
</button>
You need those bind() because you need to pass ele.id as e argument from : props.deleteStudent(e)
if you don't want to pass it that way, you can use fat arrow of ES6 as follow:
<button
onClick={() => props.deleteStudent(ele.id)}
> Delete alternative
</button>
That way above you will bind function which calls props.deleteStudent(ele.id) inside of it.
You should bind it once.If you do it twice the second one doesn't apply.
It's best practice to implement it on constructor just after super
For more read Arrow functions
It isn't required. props.deleteStudent.bind(this, ele.id) is misleading because this isn't usable inside functional component (it's either a global or undefined) but it doesn't affect deleteStudent because it's already bound to proper context.
If the intention is to bind a callback to proper context, it preferably should be bound once in class constructor:
export default class LandingPage extends Component {
deleteStudent = this.deleteStudent.bind(this); // syntactic sugar for a constructor
deleteStudent(e){
console.log('hi', this, e )
}
render(){
return(
<div>
<DisplayStudent studentData = {data}
deleteStudent = {this.deleteStudent}
/>
</div>
)
}
}
And if deleteStudent should be provided with specific argument instead of the one that will be passed on click event (event object), a cleaner way is wrapper function:
<button onClick={() => props.deleteStudent(ele.id)}>Delete</button
Binding 2 times is not needed at all. Bind is used to pass this reference inside function. So, the first bind inside LandingPage 'DisplayStudent' is enough. Also it is advisible to bind this in constructor, as everytime LandingPage re-renders it is passing a new refrence of function to DisplayStudent. The second bind in onClick is just used to pass parameter to function.
P.S. You can use arrow function to avoid such confusions

Binding this on method receiving parameters

I have an event handler which calls a fat arrow function to run a method.
import React, { Component } from 'react';
class App extends Component {
sayHi = msg => {
console.log(msg);
};
render() {
return (
<div>
<button onClick={() => this.sayHi('Hi')}>Console Hi!</button>
</div>
);
}
}
export default App;
I´m learning about contexts and bind() and, I want to convert this example to bind this. My problem is with the parameter that I´m passing when the fat arrow function executes the method, aka, 'Hi'
Is there a way to keep something like this...
<button onClick={this.sayHi('Hi')}>Console Hi!</button>
I tried different ways without good results. Mostly, focused on
constructor(props) {
super(props);
this.sayHi = this.sayHi.bind(this);
}
sayHi = () => {
console.log(msg);
};
And yes... I don´t want to move the 'Hi' to the method or constructor.
I´m trying to learn and understand. I will appreciate any kind of help or orientation.
You are mixing things. There are two cases for your situation and you are trying to use them both.
Binding to this
When do you need you bind your function to this? If you are calling your function in callback like your button (one of the cases of course) and you need to use this in this function then you need to bind it. If you don't use this then there is no need to bind it either.
sayHi() {
console.log("hi");
};
render() {
return (
<div>
<button onClick={this.sayHi}>Console Hi!</button>
</div>
);
}
}
Here, you don't need to bind it, also you can use the function with its reference since there is no argument.
constructor(props) {
super(props);
this.state = {
name: "foo",
}
this.sayHi = this.sayHi.bind(this);
}
sayHi() {
console.log(this.state.name);
};
render() {
return (
<div>
<button onClick={this.sayHi}>Console Hi!</button>
</div>
);
}
}
Here you are using this in the function, so you need to bind it in the constructor or define it as an arrow function.
Your situation
Now, your situation: You are defining your function as an arrow one, no need to bind it anymore if you will use this there. But you are not using it, then no need to use an arrow function. Also, you need to pass an argument to it. So, you need to find a way to accomplish this.
The first method, use an arrow function for onClick. Since if you don't use a callback here you can't use click.
sayHi(msg) {
console.log(msg);
};
render() {
return (
<div>
<button onClick={() => this.sayHi("hi")}>Console Hi!</button>
</div>
);
}
}
If you use like this.sayHi("hi") then this function is invoked in the first render, not with a click.
You can use .bind here as a second method also.
sayHi(msg) {
console.log(msg);
};
render() {
return (
<div>
<button onClick={this.sayHi.bind(null,"hi")}>Console Hi!</button>
</div>
);
}
}
See, we use bind but did not use this since we don't need it. We are not using this in our sayHi function.

React binding this to a class method

So i'm reading a book on React which said I have to bind my methods like
this.onClickMe = this.onClickMe.bind(this);
but it looks to work just fine without using the above code
class ExplainBindingsComponent extends Component {
onClickMe() {
console.log(this);
}
render() {
return (
<button
onClick={ () => { this.onClickMe() } }
type="button"
>
Click Me
</button>
);
}
}
but it's saying I should do something like this,
class ExplainBindingsComponent extends Component {
constructor() {
super();
this.onClickMe = this.onClickMe.bind(this);
}
onClickMe() {
console.log(this);
}
render() {
return (
<button
onClick={this.onClickMe}
type="button"
>
Click Me
</button>
);
}
}
is this.onClickMe = this.onClickMe.bind(this); still something I have to do? and if so what does it do vs my above example
There are multiple ways to bind your function to the lexical context of the React class,
one such method is to bind it in the constructor,
other method is to use class fields as arrow functions, and
the third way to bind in the render using .bind or arrow,
Each of these can be used, however its best to avoid binding in the render since a new function is returned on each render
Using class field as arrow function.
class ExplainBindingsComponent extends Component {
onClickMe = () => {
console.log(this);
}
render() {
return (
<button
onClick={ this.onClickMe }
type="button"
>
Click Me
</button>
);
}
}
Binding in render
onClick={() => this.onClickMe() }
or
onClick={this.onClick.bind(this)}
is this.onClickMe = this.onClickMe.bind(this); still something I have to do?
You don't have to do it if you use arrow functions that capture lexical this. But it is considered to be a best practice because it allows you to avoid function creation inside render.
render() {
return (
<button
/* creates new function on every render call*/
onClick={ () => { this.onClickMe() } }
type="button"
>
Click Me
</button>
);
}
vs
constructor() {
super();
// creates function once per component instance
this.onClickMe = this.onClickMe.bind(this);
}
In your case, you don't need to because you use arrow function where this is bound to a context in which arrow function is defined - in this case to your component.
this.onClickMe = this.onClickMe.bind(this)
it's necessary when you pass function without any binding so it might be invoked where this will point to another object.
For anyone who is following 'React Step by Step' link and got stuck because in the example Clock, they haven't written any bind and it has worked well, but on the next example Toggle, they started to use bind(this).
Well, you can see the function tick(){...} (Clock class) and handleClick (){...} (Toggle class) are similar, as they both use the word this inside. Well the difference between them is how they are called. In the first (Clock), it is called using arrow function (inside componentDidMount() method) and using it allows you to bind automatically the word this with the object. On the other hand, the second method is not using ()=>{}, and need to bind this with the object. So for this purpose the assignment this.handleClick = this.handleClick.bind(this); helps you.
There are 3 ways to bind this
While defining the state. Like this:
this.state = {
this.eventHandler = this.eventHandler.bind(this)
}
Change the normal function to arrow function. Like this:
eventHandler = () => {
console.log('event handler');
}
Pass arrow function directly into the props. Like this:
<input onClick={(e) => this.eventHandler(e) } />
Hope this could resolve your problem.
~RDaksh

ReactJS webpack babel: _this2 is undefined when clicking button whose function is passed via a parameter

No doubt I've missed something really obvious here but I'm trying to do the lynda tutorial "Learning React.js", it's a bit different since I'm using ES6 classes and transpiling using Babel via webpack.
The problem is executing a function being passed as a parameter to the Note class from the Board class.
I have a "Note" class which can be described as:
remove() {
this.props.onRemove(this.props.id);
}
//Notes class
render() {
return (
<div className="note">
<p>{this.props.children}</p>
<span>
<button onClick={() => this.remove() }>X</button>
</span>
</div>
);
}
Where onRemove is a function that's being passed as a prop from Board to Note like this:
//Method in Board class. I map through an array and call this function on each element to create notes.
eachNote(note) {
return (
<Note key = { note.id } id = { note.id } onRemove = { (id) => this.remove(id) }>
{ note.note }
</Note>
)
}
The remove() method in the Board class looks like this:
//Remove method in the Board class
remove(id) {
let notes = this.state.notes.filter(note => note.id !== id);
this.setState({notes});
}
When I click a Note's X button it DOES execute the local function in the note class but then DOESN'T execute the method being passed as a property (onRemove()) and instead I get (Firefox):
TypeError: _this2 is undefined
and in Chrome I get:
Cannot read property 'remove' of undefined
I don't get why it can't find the function though, I did a previous tutorial which did exactly this and it's able to find the function ok. I've probably overlooked something really simple.
[EDIT: Extra Board Info]
//Board's render method
render() {
return (
<div className='board'>
{ this.state.notes.map(this.eachNote) }
</div>
);
}
In the console it outputs what I expect.
after an afternoon of trying everything under the sun, I would like to show my solution in case anybody else had this problem.
My render method is mapping through an array of notes and creating from each element. The problem was that I wasn't passing a 'notes' object to the function which created the note element. So I fixed it by changing my render method to this:
render() {
return (
<div className='board'>
{ this.state.notes.map((note) => this.eachNote(note)) }
</div>
);
}
I'm not sure but I think this works because each Note instance has it's own this given to it. If someone has a better explanation please let me know.
If I understand correctly that the "child" component handel the click,
But the click does not propagate the the parent component (Board).
In Board, you are changing this.state (correctly) but passed along to the "chil" component, "this" changes.
Try (Board):
This.remove = this.remove.bind (this);
https://reactjs.org/docs/handling-events.html

Categories