I have problem here with this.greet() is undefined i have to bind onlick event dirrently to work, any ideas how to fix it ?
import React from 'react';
export default class Example1 extends React.Component {
constructor() {
super();
this.message = {
greeting: 'Hello',
name: 'World',
};
}
greet() {
const { greeting, name } = this.message;
console.log(`${greeting} ${name}!`);
}
onClick() {
try {
this.greet();
} catch (e) {
console.error('Why have I failed? Can you fix me?');
}
}
render() {
return (
<div>
<button onClick={this.onClick}>Greet the world</button>
</div>
);
}
}
i have tried many other ways but it didnt work out anyway.
You lost this reference, you have to bind your functions:
<button onClick={this.onClick.bind(this)}>Greet the world</button>
or pass an arrow function
<button onClick={() => this.onClick()}>Greet the world</button>
The reason you are getting undefined as a value for this.greet() is because the this keyword in JS references the current object and in this case it doesn't exist and so .greet() method is actually attached to the window object. The solution you used as you described with binding works because bind attached the method to the current object context. Now, if you don't want to bind methods, you can use arrow functions like so:
import React from 'react';
export default class Example1 extends React.Component {
constructor() {
super();
this.message = {
greeting: 'Hello',
name: 'World',
};
}
greet = () => {
const { greeting, name } = this.message;
console.log(`${greeting} ${name}!`);
}
onClick = () => {
try {
this.greet();
} catch (e) {
console.error('Why have I failed? Can you fix me?');
}
}
render() {
return (
<div>
<button onClick={this.onClick}>Greet the world</button>
</div>
);
}
}
This works because the value of this is inherited into the local scope of the methods of the component class.
if you want have "this" in your class component you should add props inside constructor invocation and also into the super
constructor(props) {
super(props);
this.greet = this.greet.bind(this) // need's to be bounded
}
Problem is this keyword.
This is because of the way this works in javascript.
this loses it's context when it gets used in callbacks.
There are two solutions for this problem. But I would recommend the arrow function solution the most.
Bind this in the onClick callback.
onClick() {
try {
this.greet();
} catch (e) {
console.error('Why have I failed? Can you fix me?');
}
}
render() {
return (
<div>
<button onClick={this.onClick.bind(this)}>Greet the world</button>
</div>
);
}
Use arrow functions for defining callbacks, ( personally recommended )
onClick = () => {
try {
this.greet();
} catch (e) {
console.error('Why have I failed? Can you fix me?');
}
}
render() {
return (
<div>
<button onClick={this.onClick}>Greet the world</button>
</div>
);
}
First your function signature should be descriptive and then you can call the function like this
<button onClick={this.onClick()}>Greet the world</button>
Related
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 2 years ago.
I have a class component which has a function inside it named printData() I want to make use of the states and props variable of the class inside this function. How can I do it?
Code -
class ReadData extends Component {
constructor(props) {
super(props);
this.state = {
data: ""
}
}
componentDidMount() {
this.setState({ data: "Hello World" })
}
printData(props) {
console.log(this.props.data)
}
render() {
return (
<div>
<p>{this.state.data}</p>
<button onClick={this.printData}>Print</button>
</div>
)
}
}
The actual code is different. This is an example of what I am trying to implement. The console says
Uncaught (in promise) TypeError: Cannot read property 'props' of undefined
Using this.state.data instead of this.props.data also did not work.
Note: The render return successfully prints the desired output on the
window. Also, I want to make use of Class component and not functional component
You need to either bind the function or use arrow functions () => {} for this to work.
See doc: https://reactjs.org/docs/handling-events.html
class ReadData extends Component {
constructor(props) {
super(props);
// This binding is necessary to make `this` work in the callback
this.printData = this.printData.bind(this);
}
printData() {
console.log(this.props.data)
}
render() {
return (
<div>
<p>{this.state.data}</p>
<button onClick={this.printData}>Print</button>
</div>
)
}
}
or
class ReadData extends Component {
// Use arrow function to make `this` work in the callback
printData = () => {
console.log(this.props.data)
}
render() {
return (
<div>
<p>{this.state.data}</p>
<button onClick={this.printData}>Print</button>
</div>
)
}
}
Im doing ReactJS course in Codeacademny and they confused me.
(EDIT - full code) Photo of the code :
and there's no constructor or anywhere call to any bind method for the scream class method.
However in further exercises they tell you can't do that.
I probably miss something.
Apparently this.scream is an arrow function. Arrow function does not require binding. It points to the right context by default.
scream = () => { ... }
and there's no constructor or anywhere call to any bind method for the scream class method.
You only have to bind this to the component instance when the method actually uses this internally.
That's not the case in your example, so there is no need to bind it. No matter how the method is executed, it will always produce the same output.
Here is an example without React to demonstrate the difference:
var obj = {
value: 42,
method1() { // doesn't use `this`
console.log("yey!");
},
method2() { // uses `this`
console.log(this.value);
},
};
obj.method1(); // works
obj.method2(); // works
var m1 = obj.method1;
var m2 = obj.method2;
m1(); // works
m2(); // BROKEN!
var m2bound = obj.method2.bind(obj);
m2bound(); // works
scream = () => { ... }
render() {
return <button onClick={()=>this.scream()}>AAAAAH!</button>;
}
ou have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.
This is not React-specific behavior; it is a part of how functions work in JavaScript. Generally, if you refer to a method without () after it, such as
onClick={this.handleClick}, you should bind that method.
When you define a component using an ES6 class, a common pattern is for an event handler to be a method on the class. For example, this Toggle component renders a button that lets the user toggle between “ON” and “OFF” states:
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// This binding is necessary to make `this` work in the callback
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(state => ({
isToggleOn: !state.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);```
You can simply use an arrow function (no need to bind in constructor).
scream = () => { console.log('Here') }
render() {
return <button onClick={this.scream}>AAAAAH!</button>;
}
Or you can call this function inline by.
render() {
return <button onClick={() => console.log('Here')}>AAAAAH!</button>;
}
You should use arrow functions for event handling to bind the function to the object. Other solution is to auto bind each function in the constructor like :
class Test{
constructor(){
Object.getOwnPropertyNames(Test.prototype).forEach(
method => this[method] = this[method].bind(this));
}
Read about #AutoBind decorator for more details.
I want to call a method inside another method like this, but it is never called.
Button:
<span onClick={this.firstMethod()}>Click me</span>
Component:
class App extends Component {
constructor(props) {
super(props);
this.state = {..};
}
firstMethod = () => (event) => {
console.log("button clicked")
this.secondMethod();
}
secondMethod = () => (event) => {
console.log("this is never called!")
}
render() {..}
}
The first method is called, but not the second one. I tried to add to the constructor
this.secondMethod = this.secondMethod.bind(this);
which is recommended in all the other solutions but nothing seems to work for me. How can I call the second method correctly?
There are two problems here.
First one: You are defining your functions wrong.
firstMethod = () => (event) => {
console.log("button clicked")
this.secondMethod();
}
Like this, you are returning another function from your function. So, it should be:
firstMethod = ( event ) => {
console.log("button clicked")
this.secondMethod();
}
Second: You are not using onClick handler, instead invoking the function immediately.
<span onClick={this.firstMethod()}>Click me</span>
So, this should be:
<span onClick={() => this.firstMethod()}>Click me</span>
If you use the first version, yours, when component renders first time your function runs immediately, but click does not work. onClick needs a handler.
Here, I totally agree #Danko's comment. You should use this onClick with the function reference.
<span onClick={this.firstMethod}>Click me</span>
With this method, your function is not recreated every time your component renders since it uses your handler function with its reference. Also, no struggle writing the handler manually.
Lastly, if you define your functions as an arrow one, you don't need to .bind them.
Here is the working code.
class App extends React.Component {
firstMethod = () => {
console.log("button clicked")
this.secondMethod();
}
secondMethod = () =>
console.log("this is never called!")
// or maybe even better not using an arrow function for the
// second method since it is already bound to `this` since we
// invoke it from the firstMethod. For details, look the comments please.
/* secondMethod() {
console.log("this is never called!")
} */
render() {
return(
<span onClick={this.firstMethod}>Click me</span>
)
}
}
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>
Instead of firstMethod = () => (event) try firstMethod = (event) => and instead of secondMethod = () => (event) => { try secondMethod = (event) => {
The bad news is that you can't bind arrow functions because they're lexically bound. See:
Can you bind arrow functions?
The good news is that "lexical binding" means that they should already have App as their this, i.e. it should would without explicitly binding. You'd likely redefining them as undefined, or some other odd thing by treating them this way in the constructor.
Try this, it works for me.
firstMethod = () => {
console.log("click handler for button is provided")
return (event) => this.secondMethod(event);
}
secondMethod = (event) => {
console.log("This is being called with", event);
}
Your second method returns a new function, which is redundant.
Also, your second method can be not bound, since the first method has the context already.
secondMethod = () => (event) => { ... } should be secondMethod(evnt) { ... }
Here is the working and optimized example https://codesandbox.io/s/pkl90rqmyj
Can you check this way using this url: https://codesandbox.io/s/q4l643womw
I think you're using wrong bind methods but here you can see an example
class App extends Component {
constructor() {
super();
this.state = {
num: 1,
};
this.firstMethod = this.firstMethod.bind(this);
this.secondMethod = this.secondMethod.bind(this);
}
firstMethod() {
this.secondMethod();
}
secondMethod() {
this.setState({
num: 2
});
}
render() {
return (
<div className="App">
<button onClick={this.firstMethod}>click</button>
<label>{this.state.num}</label>
</div>
);
}
}
I was expecting to see undefined being logged when the "Without binding" button was clicked because when you pass a method reference plainly as a callback, it shouldn't be called with the right this context, but with an arrow function, it should.
However, I saw that the callback function could access this and the value of this.state.number was logged properly. The method reference and arrow function performed the exact same. Why?
This does not have to do with arrow function class properties, it has to do with passing a reference to a method as a callback to setState as opposed to an arrow function.
class Hello extends React.Component {
constructor(props) {
super(props);
this.state = {
number: 1,
};
}
onClickWithThisBindingInCallback = () => {
this.setState({ number: 2 }, () => { this.myCallback(); });
};
onClickWithoutThisBindingInCallback = () => {
const myCb = this.myCallback;
this.setState({ number: 3 }, myCb);
};
myCallback() {
console.log(this.state.number);
}
render() {
return (
<div className="App">
<button onClick={this.onClickWithThisBindingInCallback}>With binding</button>
<button onClick={this.onClickWithoutThisBindingInCallback}>Without binding</button>
</div>
);
}
}
ReactDOM.render(
<Hello name="World" />,
document.getElementById('container')
);
<script src="https://unpkg.com/react#16.2.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.2.0/umd/react-dom.development.js"></script>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>
React calls the callback function of setState with the component's instance this, as seen by this line of code.
Credits: #Li357
It is because you are given a lambda function to it:
onClickWithThisBinding = () => {
A lambda function is executed in it's given context. So the binding is actually onClick={() => { .. }}. That is why it has the this context.
This is due to the use of the arrow function.
Arrow functions always have the same this of their surrounding code.
See more here.
If you want the method not to be bound to that specific class you can use a normal function like this.
onClickWithoutThisBinding() {
const myCb = this.myCallback;
this.setState({ number: 3 }, myCb);
};
When I try to execute the below code, the value of this within the function renderContents is undefined.
I had thought that fat arrow functions bound this automatically. Is this not the case? If not, how can I ensure that this is passed to the function renderContents?
Code sample:
class Box extends React.Component {
renderContents = () => {
console.log(this); // undefined
return (
<div></div>
)
}
render() {
const {
someValue,
} = this.props;
return (
<div>
{someValue ? this.renderContents() : null}
</div>
);
}
}
There is nothing wrong. I just called it like this:
ReactDOM.render((<Box someValue={true} />), document.getElementById('content'));
and I got the value of this:
So I think the problem would be, you aren't calling it right, are you setting someValue??
You make mistake in renderContent method. You declare it as function and it have no context of your component.
Please try to declare methods like this:
renderContent() {
...your code...
}
Instead this:
renderContent = () => {}
Have you tried to add an constructor method?
constructor(props) {
super(props)
}
EDIT:
Instead of using arrow functions, you could bind the context in constructor like this:
class Box extends React.Component {
constructor(props) {
super(props)
this.renderContents = this.renderContents.bind(this)
}
renderContents() {
console.log(this);
return (
<div></div>
)
}
render() {
const {
someValue,
} = this.props;
return (
<div>
{someValue ? this.renderContents() : null}
</div>
);
}
}
In react classes just some methods are implicitly binded (render, componentDidMount, componentWillUnmount, etc.), other methods you have to bind manually in constructor or use arrow functions.