Why is the this keyword inside clickHandler undefined? - javascript

I was following a YouTube tutorial on eventHandling when I got confused with the implementation of this keyword.
In the code below, the this keyword inside of clickHandler function gives the value of undefined. The instructor said that it is because that's how JavaScript works. But when I searched online I found out that this keyword when used inside a function of a class, points to the object itself.
This might be a stupid question to ask but since I am new to JavaScript any help will be appreciated
class EventBind extends Component {
constructor(props) {
super(props);
this.state = {
message: "Hello",
};
}
clickHandler() {
// this.setState({
// message : 'Goodbye'
// })
console.log(this);
}
render() {
return (
<div>
<div>{this.state.message}</div>
<button onClick = {this.clickHandler}>Click</button>
</div>
);
}
}

This is cause you have not bound the clickHandler to this.
Try below code
class EventBind extends Component {
constructor(props) {
super(props);
this.clickHandler = this.clickHandler.bind(this);
...
}
clickHandler() {
...
}
...
}
See here for more info: https://reactjs.org/docs/faq-functions.html

Related

Accessing component variables from methods

In my app, I have a component with a state variable and a component variable in its constructor. However, if I try accessing them from my method by resizing the window, I get undefined and cannot read property 'test' of undefined.
import React from 'react';
class Testapp extends React.Component {
constructor(props) {
super(props);
this.state = {test: "he"};
this.test = "hu";
window.addEventListener('resize', this.testCallback);
}
testCallback() {
console.log(this.test);
console.log(this.state.test);
}
render() {
return( <p>Hello world</p> );
}
}
export default Testapp;
How can I access these attributes from the method?
Your function as is does not have access to the this variable in the correct context.
The easiest solution is to convert to an arrow function
testCallback = () => {
console.log(this.test);
console.log(this.state.test);
}
This will give your function the correct context of this.
Alternatively you could manually bind it in your constructor.
constructor(props) {
super(props);
this.state = {test: "he"};
this.test = "hu";
window.addEventListener('resize', this.testCallback);
this.testCallback = this.testCallback.bind(this);
}
Just use an arrow function instead. Alternatively, you can bind 'this' to the method.

It is possible to call class function from outside class

I am trying to call function outside from class and update the state of class. Is this correct way ?
function myFunc() {
this.Test("test")
}
class Notification extends Component {
constructor(props) {
super(props);
this.state = {
demoState:''
};
}
Test(data){
this.setState({
demoState:data
})
}
render(){
return(<div/>)
}
}
You haven't provided function usage in your example.
It's correct way, that's how the most function works. But don't tease react.js by using this argument - just pass an argument to myFunc
YES pass this an argument to myFunc.
function myFunc(this /* <----- */) {
this.Test("test")
}
Then call myFunc from inside of class like this:
myFunc(this);
May be, you need to pass object of that class to change the state. Have a look at myFunc & Notification.Test function changes.
function myFunc() {
let notification = new Notification({});
notification.Test("test");
console.log(notification.state);
}
class Notification extends Component {
constructor(props) {
super(props);
this.state = {
demoState: ''
};
}
Test(data) {
this.state = {
demoState: data
};
}
render() {
return ('<div/>')
}
}

React.js how to make a correct callback prop function? [duplicate]

This question already has answers here:
Unable to access React instance (this) inside event handler [duplicate]
(19 answers)
Closed 5 years ago.
Im working with a react.js app, and I remember that I was able to pass a callback function from a child to a parent with pops, the thing is I cant achieve to do this again (I'd like to keep it simple, without Flux libraries):
So my parent App:
class App extends Component {
constructor(props) {
super(props);
}
showViewAction(viewToShow){
console.log(viewToShow);
}
render() {
return (
<div>
<AppMenu showView={this.showViewAction}/>
</div>
);
}
}
And my child AppMenu:
class AppMenu extends Component{
constructor(props) {
super(props);
}
showCirculares(){
this.props.showView("circulares");
}
render(){
return(
<div>
<MenuButton onClick={this.showCirculares} buttonTitle="SomeOtherProp"/>
</div>
);
}
}
Everything I try, I always get:
Cannot read property 'props' of undefined at showCirculares;
I know this will be resolved with a simple task, and that this is basic React.js stuff, its just that I cant find a solution for this!! What am I doing wrong?
Looks like you need to bind the this context to your callback functions. Do so in the constructor function like so:
App
class App extends Component {
constructor(props) {
super(props);
this.showViewAction = this.showViewAction.bind(this);
}
showViewAction(viewToShow){
console.log(viewToShow);
}
render() {
return (
<div>
<AppMenu showView={this.showViewAction}/>
</div>
);
}
}
AppMenu
class AppMenu extends Component{
constructor(props) {
super(props);
this.showCirculares = this.showCirculares.bind(this);
}
showCirculares(){
this.props.showView("circulares");
}
render(){
return(
<div>
<MenuButton onClick={this.showCirculares} buttonTitle="SomeOtherProp"/>
</div>
);
}
}
Why? The short version is that unless you bind this, when your functions run the value of this is undefined. What you want is the context of the component instead, so you have to manually bind the functions to it.
You need to bind the showCirculares with the class so that it does not have this undefined. Following are the ways to do this.
Bind your method in constructor like this
constructor(props) {
super(props);
this.showCirculares = this.showCirculares.bind(this)
}
showCirculares(){
this.props.showView("circulares");
}
Or simply use arrow function like this
showCirculares = () => {
this.props.showView("circulares");
}
You can bind explicitly showCirculares using the bind function like #jered said, or you can use arrow functions, that are implicitly bound to the calling this.
<MenuButton onClick={() => this.showCirculares()} buttonTitle="SomeOtherProp"/>

es6 class method unable to access local state? [duplicate]

This question already has answers here:
Unable to access React instance (this) inside event handler [duplicate]
(19 answers)
Closed 6 years ago.
I'm pretty confident i'm doing this wrong, i'm unable to console.log this.state.greeting however if I reference this.state.greeting inside the return statement it works, i'm confused why it doesn't work within the class method
class Test extends React.Component {
constructor (props) {
super(props)
this.state = {
greeting: 'test'
}
}
greeting () {
console.log(this.state.greeting)
}
render () {
return (
<p onClick={this.greeting}>test</p>
)
}
}
export default Test
You need to bind it. Here are two options:
class Test extends React.Component {
constructor (props) {
super(props)
this.state = {
greeting: 'test'
}
}
greeting () {
console.log(this.state.greeting)
}
render () {
return (
<p onClick={this.greeting.bind(this)}>test</p>
)
}
}
// OR THIS
class Test extends React.Component {
constructor (props) {
super(props)
this.state = {
greeting: 'test'
}
this.greeting = this.greeting.bind(this);
}
greeting () {
console.log(this.state.greeting)
}
render () {
return (
<p onClick={this.greeting}>test</p>
)
}
}
There are actually two tricks to this one. You can either use the bind function in your constructor like so:
this.greeting = this.greeting.bind(this);
or if you have babel setup correctly with es6 and presets then you can do it a better way by using anonymous lambdas. Inside your .babelrc file it should look like this:
{
"presets": [
"react",
"es2015",
"stage-1"
]
}
and have the proper dependencies installed then you can use the es6 functions like this:
class Test extends React.Component {
constructor (props) {
super(props);
}
greeting = () => {
console.log(this.state.greeting)
}
render = () => {
return (
<p onClick={this.greeting}>test</p>
);
}
}
export default Test
Personally I love the second option. It doesn't bloat up your constructor, and the anonymous lambdas are nicer to type than function every time.

reactjs typescript event this undefined

I got the following component written in typescript. (type definitions from definitelytyped.org). I got the onWheel event bound to a function. But when ever it is fired this is undefined, so how am I supposed to access the referenced element this.div and if I would want/need to change the state how should do that?
import React = require('react');
interface fooProps {
src: string;
}
class foo extends React.Component<fooProps, {}>
{
private div: HTMLDivElement;
public onWheel(e: React.WheelEvent): void {
e.preventDefault();
e.stopPropagation();
//Do stuff with the div, but 'this' is undefined!!
this.div;
}
public render(): JSX.Element {
return (
<div ref={(ref) => this.div = ref} onWheel= { this.onWheel} >
<img src={ this.props.src } />
</div >)
}
}
Don't know about Typescript, but I'm guessing it's the same thing as when creating components using the similar ES2015 syntax which will need a constructor, and function binding to make a reference to this.onWheel work.
So in ES2015,
class foo extends React.Component {
constructor(props) {
super(props);
// Magic happens here:
this.onWheel = this.onWheel.bind(this)
// Now each instance of foo can use this.onWheel
}
onWheel () {
....
}
render (){
....
}
}
Another solution if you don't want to bind each function in the constructor is to use lambdas:
class foo extends React.Component {
constructor(props) {
super(props);
}
// The lambda creates a lexical scope so it's autobound
onWheel = () => {
....
}
render () {
....
}
}
You can read more here.
onWheel= { this.onWheel}
onWheel={this.onWheel.bind(this)}
The simple thing would be converting it into an arrow function which binds automatically:
public onWheel = (e: React.WheelEvent): void => {
e.preventDefault();
e.stopPropagation();
//Do stuff with the div, and yes you can work with 'this' in this function
this.div;
}

Categories

Resources