I am a complete newbie in react native, react.js, and javascript. I am Android developer so would like to give RN a try.
Basically, the difference is in onPress
;
This code shows 'undefined'
when toggle() runs:
class LoaderBtn extends Component { constructor(props) { super(props); this.state = { loading: false }; } toggle() { console.log(this.state); // let state = this.state.loading; console.log("Clicked!") // this.setState({ loading: !state }) } render() { return ( <Button style={{ backgroundColor: '#468938' }} onPress={this.toggle}> <Text>{this.props.text}</Text> </Button> ); } }
but this code works:
class LoaderBtn extends Component { constructor(props) { super(props); this.state = { loading: false }; } toggle() { console.log(this.state); // let state = this.state.loading; console.log("Clicked!") // this.setState({ loading: !state }) } render() { return ( <Button style={{ backgroundColor: '#468938' }} onPress={() => {this.toggle()}}> <Text>{this.props.text}</Text> </Button> ); } }
Can you explain me the difference, please?
In Java / Kotlin we have method references, basically it passes the function if signatures are the same, like onPress = () => {}
and toggle = () => {}
But in JS it doesn't work :(
To check for undefined in React, use a comparison to check if the value is equal or is not equal to undefined , e.g. if (myValue === undefined) {} or if (myValue !== undefined) {} . If the condition is met, the if block will run.
This is because when you use an arrow function, the event handler is automatically bound to the component instance so you don't need to bind it in the constructor. When you use an arrow function you are binding this lexically.
The "cannot read property 'setState' of undefined" error occurs when a class method is called without having the correct context bound to the this keyword. To solve the error, define the class method as an arrow function or use the bind method in the classes' constructor method.
State updates in React are asynchronous; when an update is requested, there is no guarantee that the updates will be made immediately. The updater functions enqueue changes to the component state, but React may delay the changes, updating several components in a single pass.
The issue that in the first example toggle()
is not bound to the correct this
.
You can either bind it in the ctor:
constructor(props) { super(props); this.toggle = this.toggle.bind(this); ...
Or use an instance function (OK under some circumstances):
toggle = () => { ... }
This approach requires build changes via stage-2
or transform-class-properties
.
The caveat with instance property functions is that there's a function created per-component. This is okay if there aren't many of them on the page, but it's something to keep in mind. Some mocking libraries also don't deal with arrow functions particularly well (i.e., arrow functions aren't on the prototype, but on the instance).
This is basic JS; this article regarding React Binding Patterns may help.
I think what is happening is a matter of scope. When you use onPress={this.toggle}
this is not what you are expecting in your toggle function. However, arrow functions exhibit different behavior and automatically bind to this
. You can also use onPress={this.toggle.bind(this)}
.
Further reading -
ES6 Arrow Functions
.bind()
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