ReactJS bind method to class component - javascript

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.

Related

React component what's the difference between callbacks implement methods

import React from 'react';
import ChildComponent from './ChildComponent';
class SampleComponent extends React.Component {
sampleCallbackOne = () => {
// does something
};
sampleCallbackTwo = () => {
// does something
};
render() {
return (
<div>
<ChildComponent
propOne={this.sampleCallbackOne}
propTwo={() => this.sampleCallbackTwo()}
/>
</div>
);
}
}
export default SampleComponent;
In this example, I have an onClick event that I am handling and saw that I can successfully pass this into the props of the component in two ways.
I was wondering what exactly the difference is in both ways since they appear to function in the same manner?
Why do both ways work?
It is a common point that seems weird.
Refer details in document of handling-events
// This binding is necessary to make `this` work in the callback
this.handleClick = this.handleClick.bind(this);
handleClick() {
console.log('this is:', this);
}
<button onClick={this.handleClick}>
If you don't add () behind this.handleClick, you need to bind this in your constructor, otherwise, you may want to use the next two methods:
A. public class field syntax
which is enabled by default in Create React App
handleClick = () => {
console.log('this is:', this);
}
<button onClick={this.handleClick}>
B. arrow functions
which may cause performance problems and is not recommended, refer to the document above.
// The same on event handling but different in:
<button
onClick={(e) => this.deleteRow(id, e)} // automatically forwarded, implicitly
/>
<button
onClick={this.deleteRow.bind(this, id)} // explicitly
/>
Sample
Basically in our practice, we use public class field syntax with params which would look like below:
// No need to bind `this` in constructor
// Receiving params passed by elements as well as getting events of it
handler = (value: ValueType) => (event: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => {
// Do something with passed `value` and acquired `event`
}
<NumberFormat
...
onBlur={this.handler(someValue)} // Passing necessary params here
/>
We can share the handler function by passing different params to it.
// Justify via keyword of stored content in flat data structure
handler = (value: string) => (event: React.ChangeEvent<HTMLInputElement>, id: ValidationItems) => {
// Do something with
// passed `value`,
// acquired `event`,
// for each element diffenced via `id`
};
<YourComponent
id="ID_1"
value={store.name1}
onChange={this.handler("name1")}
/>;
<YourComponent
id="ID_2"
value={store.name2}
onChange={this.handler("name2")}
/>;
// ... more similar input text fields
<ChildComponent
propOne={this.sampleCallbackOne}
propTwo={() => this.sampleCallbackTwo()}
/>
for propOne: here you are passing the reference of sampleCallbackOne.
for propTwo: you are wrapping your sampleCallbackTwo in another function.
In both the case you will get the same results

Call method within method in reactjs

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>
);
}
}

Why this.state is undefined in react native?

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 :(
The issue is that in the first example toggle() is not bound to the correct this.
You can either bind it in the constructor:
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()
What is happening in this first example is that you have lost scope of "this". Generally what I do is to define all my functions in the constructor like so:
constructor(props) {
super(props);
this.state = { loading: false };
this.toggle = this.toggle.bind(this);
}
In the second example, you are using ES6 syntax which will automatically bind this (which is why this works).
Then inside of you onPress function, you need to call the function that you built. So it would look something like this,
onPress={this.toggle}

ReactJS - MouseClick gets triggered without a click

I'm new to React.JS and trying to create a click event on an element inside a rendered component.
Here is my code:
class InputPanel extends React.Component{
handleClick(i,j) {
this.props.dispatch(actions.someMethod());
// e.preventDefault();
}
render() {
const { dispatch, board } = this.props;
return(
<div>
{
board.map((row, i) => (
<div>{row.map((cell, j) => <div className="digit"
onClick={this.handleClick(i,j)}>{cell}</div>)}</div>
))
}
</div>
);
}
};
My problem is that "handleClick" gets triggered after page load without any mouse clicked!
I've read about React.JS lifecycle and thought about registering to click event in componentDidMount method, but i'm really not sure about it:
Is there any easier way ? (or: Am I doing something wrong that triggers click ?)
If adding componentDidMount method is the right way - how can I get the element I create in render method ?
You should not use .bind when passing the callback as a prop. There’s a ESLint rule for that. You can read more about how to pass callback without breaking React performance here.
Summary:
make sure you aren’t calling functions but pass functions as handlers in your props.
make sure you do not create functions on every render, for that, you need to bind your handlers in parent component, pass correct the required data (such as indices of iteration) down the child component and have it call the parent’s handler with the data it has
Ideally you’d create another component for the rows and pass the callback there. Moreover, ideally you’d bind the onClick in the parent component’s constructor (or componentWillMount). Otherwise every time render runs a new function is created (in both anonymous function handler () => { this.onClick() } and this.onClick.bind and defeat React’s vdom diff causing every row to rerender every time.
So:
class InputPanel extends React.Component{
constructor() {
super();
this.handleClick = this.handleClick.bind(this);
}
handleClick(i,j) {
this.props.dispatch(actions.someMethod());
// e.preventDefault();
}
render() {
const { dispatch, board } = this.props;
return(
<div>
{board.map((row, i) => <div>
{row.map((cell, j) => <Digit
onClick={this.handleClick})
i={i}
j={j}
cell={cell}
/>)}
</div>)}
</div>
);
}
};
class Digit extends React.Component {
constructor() {
super();
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.props.onClick(this.props.i, this.props.j);
}
render() {
return <div
className="digit"
onClick={this.handleClick}
>{this.props.cell}</div>
}
}
It is because you are calling this.handleClick() function instead of providing a function definition as onClick prop.
Try changing the div line like this:
<div className="digit" onClick={ () => this.handleClick(i,j) }>{cell}</div>
Also you have to bind this.handleClick() function. You can add a constructor and bind all the member functions of a class there. that's the best practice in ES6.
constructor(props, context) {
super(props, context);
this.handleClick = this.handleClick.bind(this);
}
You call this function in render. You should only transfer function and bind params.
onClick={this.handleClick.bind(null,i,j)}
You should use .bind().
class InputPanel extends React.Component{
handleClick(i,j) {
this.props.dispatch(actions.someMethod());
// e.preventDefault();
}
render() {
const { dispatch, board } = this.props;
return(
<div>
{
board.map((row, i) => (
<div>{row.map((cell, j) => <div className="digit"
onClick={this.handleClick.bind(null,i,j)}>{cell}</div>)}</div>
))
}
</div>
);
}
};

Why is my onClick being called on render? - React.js

I have a component that I have created:
class Create extends Component {
constructor(props) {
super(props);
}
render() {
var playlistDOM = this.renderPlaylists(this.props.playlists);
return (
<div>
{playlistDOM}
</div>
)
}
activatePlaylist(playlistId) {
debugger;
}
renderPlaylists(playlists) {
return playlists.map(playlist => {
return <div key={playlist.playlist_id} onClick={this.activatePlaylist(playlist.playlist_id)}>{playlist.playlist_name}</div>
});
}
}
function mapStateToProps(state) {
return {
playlists: state.playlists
}
}
export default connect(mapStateToProps)(Create);
When I render this page, activatePlaylist is called for each playlist in my map. If I bind activatePlaylist like:
activatePlaylist.bind(this, playlist.playlist_id)
I can also use an anonymous function:
onClick={() => this.activatePlaylist(playlist.playlist_id)}
then it works as expected. Why does this happen?
You need pass to onClick reference to function, when you do like this activatePlaylist( .. ) you call function and pass to onClick value that returned from activatePlaylist. You can use one of these three options:
1. using .bind
activatePlaylist.bind(this, playlist.playlist_id)
2. using arrow function
onClick={ () => this.activatePlaylist(playlist.playlist_id) }
3. or return function from activatePlaylist
activatePlaylist(playlistId) {
return function () {
// you code
}
}
I know this post is a few years old already, but just to reference the latest React tutorial/documentation about this common mistake (I made it too) from https://reactjs.org/tutorial/tutorial.html:
Note
To save typing and avoid the confusing behavior of this, we will use
the arrow function syntax for event handlers here and further below:
class Square extends React.Component {
render() {
return (
<button className="square" onClick={() => alert('click')}>
{this.props.value}
</button>
);
}
}
Notice how with onClick={() => alert('click')}, we’re passing a
function as the onClick prop. React will only call this function after
a click. Forgetting () => and writing onClick={alert('click')} is a
common mistake, and would fire the alert every time the component
re-renders.
This behaviour was documented when React announced the release of class based components.
https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html
Autobinding
React.createClass has a built-in magic feature that bound all methods to this automatically for you. This can be a little confusing for JavaScript developers that are not used to this feature in other classes, or it can be confusing when they move from React to other classes.
Therefore we decided not to have this built-in into React's class model. You can still explicitly prebind methods in your constructor if you want.
import React from 'react';
import { Page ,Navbar, Popup} from 'framework7-react';
class AssignmentDashboard extends React.Component {
constructor(props) {
super(props);
this.state = {
}
onSelectList=(ProjectId)=>{
return(
console.log(ProjectId,"projectid")
)
}
render() {
return (
<li key={index} onClick={()=> this.onSelectList(item.ProjectId)}></li>
)}
The way you passing the method this.activatePlaylist(playlist.playlist_id), will call the method immediately. You should pass the reference of the method to the onClick event. Follow one of the below-mentioned implementation to resolve your problem.
1.
onClick={this.activatePlaylist.bind(this,playlist.playlist_id)}
Here bind property is used to create a reference of the this.activatePlaylist method by passing this context and argument playlist.playlist_id
2.
onClick={ (event) => { this.activatePlaylist.(playlist.playlist_id)}}
This will attach a function to the onClick event which will get triggered on user click action only. When this code exectues the this.activatePlaylist method will be called.

Categories

Resources