how to mixin react class arrow function - reactjs

I may not understand the => in react component class. handler prints true in below code.
class X extends Component {
handler = () => {console.log(this instanceof X)}
render() {
return <a onClick={this.handler}>xxx</a>
}
}
But I can't mixin handler in below code. handler always returns false. I want to know how to bind this in the Object.assign, so it can return true too. Thanks.
class X extends Component {
render() {
return <a onClick={this.handler}>xxx</a>
}
}
Object.assign(X.prototype, {
handler: () => {console.log(this instanceof X)}
})

Arrow function are not meant to be used everywhere such as Constructor which can only be function !
The most common use case for arrow functions is "lambdas" which do not redefine this, often used as a callback to some function.
In your first example your arrow function will bind your context which is your class reference, so this instanceof X is true however :
Object.assign(X.prototype, {
handler: () => {console.log(this instanceof X)}
})
Here you're trying to do the same but this, is no more your class but here your context will be window or something else..

Related

What is the difference between these methods in class

I'm new to react and I can not understand the difference between these two methods in a class
doSomething=()=>{
console.log("Something")
}
and
doSomething() {
console.log("Something")
}
Both looks like they do the same thing
Once again this has been introduced in new ES7 syntax. You can read more about it here
https://www.reactnative.guide/6-conventions-and-code-style/6.4-es7-features.html
Basically in old ES6 we had to write classes and binding methods like this (copied from the documentation)
class SomeComponent extends Component {
_incrementCounter() {
this.setState({count: this.state.count+1})
}
constructor() {
this._incrementCounter = this._incrementCounter.bind(this);
}
...
}
In new ES7 you can simply use arrow function
class SomeComponent extends Component {
_incrementCounter = () => {
this.setState({count: this.state.count+1})
}
...
}
It is up to you what you gonna use. Both ways are ok to use but as you can see ES7 syntax is much shorter and easier to read
doSomething=()=>{
console.log("Something")
}
The above one is using fat arrow functions. You can access this (the class instance) inside this function without binding.
The second one is just defining a function. You will not have access to this here. You cannot use this inside that function. To use this you need to bind the function in constructor or in some other place
Eg;
this.doSomething = this.doSomething.bind(this);
More on this keyword
This is not quite so React specific but it does have implications when passing these functions around to other contexts.
Classes in ES6 don't require binding to allow the use of this within their methods, for example the following is perfectly valid:
class TestClass {
constructor() {
this.variable = 'a variable';
}
method() {
console.log(this.variable)
}
}
const thing = new TestClass();
thing.method(); // will output 'a variable'
The reason you would specifically want to use an arrow function is so you can pass this function down to a component as a prop or use it as part of a button action. Once you have passed the method reference away it no longer has access to this.
class TestComponent extends Component {
constructor() {
this.variable = 'a variable';
}
method() {
console.log(this.variable)
}
render() {
return <AnotherComponent method={this.method} />
}
}
Calling this.method from inside <AnotherComponent> will produce an error. This is where the arrow function comes in.
class TestComponent extends Component {
constructor() {
this.variable = 'a variable';
}
method = () => {
console.log(this.variable)
}
render() {
return <AnotherComponent method={this.method} />
}
}
method now uses an arrow function and 'lexically binds' this which basically means it takes its this from its surrounding context, in this case the class (component) it has been defined in.

Which object owns react click handler code?

I know that when using React class methods arrow functions are a great way to lock in this. For example I might have a click handler:
clickHandler = () => {
// some code using 'this'
// eg this.state
}
// ... and in the render method
<button onClick={() => this.clickHandler()}>Test Button</button>
However if I were to use a non-arrow function syntax what object owns the code? That is, what is this?
I have tried the following but Typescript will not compile:
clickHandler = function() {
console.log(this); // also tried to coerce this as any type
}
// Error: 'this' implicitly has type 'any' because it does not have a type annotation.ts(2683)
It depends on how you call the function and whether or not you bind it.
class Test extends React.Component {
clickHandler = function() {
console.log(this);
}
render() {
return (
<div>
<button onClick={this.clickHandler}>Option A</button>
<button onClick={this.clickHandler.bind(this)}>Option B</button>
<button onClick={() => this.clickHandler()}>Option C</button>
</div>
);
}
}
With the Option A button, the click handler is passed directly to the <button /> element. Since React assumes you bind this and won't do it for you, the this inside clickHandler will be undefined.
With the Option B button we're explicitly binding this.clickHandler to this, in which case the this inside clickHandler will refer to that specific instance of the Test component.
For Option C (which is what you're doing in your question) we are not setting this.clickHandler as the onClick handler, but we're defining a new arrow function that calls this.clickHandler. In this case, the new arrow function will automatically get the Test component as this and that one is passed along to clickHandler.
Note that the Option A version will allow components to explicitly bind the handler:
class Button extends React.Component {
render() {
return (
<button
onClick={this.props.onClick.bind(this)}
children={this.props.children}
/>
);
}
}
class Test extends React.Component {
clickHandler = function() {
console.log(this);
}
render() {
return <Button onClick={this.clickHandler}>Click</Button>;
}
}
In this case, this within Test.clickHandler() will actually be a reference to the Button instance.
Your "this" will be 'undefined' because React calls your function behind the scenes and it doesn't call it from the object instance (I.E MyComponent.onClickHandler(e)) it calls it like this (onClickHandler(e))
A simplified model of what's happening without React involved looks something like this.....
class FakeReactComponent {
myName() {
console.log(this);
}
}
// this is what you give a onClick prop on an element.
const functionPassedToOnClick= new FakeReactComponent().myName;
console.log(
functionPassedToOnClick() // this is how react calls it (this is undefined)
)
On method to get around this is to bind "this" of the function in the constructor of the component I.E
constructor(props: IProps) {
super(props);
this.onClickHandler = this.onClickHandler.bind(this);
}
This is actually the 'best practice' way to define all functions within a class for React Components as arrow functions don't go on the classes prototype and therefore fresh functions are created for every new React instance of that component; however with non-arrow functions each instance goes on the prototype and therefore reused for each react component instance.
Tricks like autobind are also not best practice because binding every function's this is unneccessary because only functions being called by React need to have their this bound and 99% of the time that's only functions being used as event handlers.

onClick not working after defining multiple onClick events

I had an onClick event define which was working fine:
onClick={this.props.removeFunctionsData.bind(null,this.props.path,this.props.obj.data_type)}
Now I want to define two events on the same onClick. I tried doing this:
onClick={(e)=>{this._onClose(e);this.props.removeFunctionsData.bind(null,this.props.path,this.props.obj.data_type);}}
But in this case only this._onClose(e) works and not the original one. How can I fix this?
Inside your component, define a handleClick function, using the ES6 arrow function syntax. This syntax doesn't create a new context, therefore you don't have to bind this inside the constructor or when calling it.
Here's an example using the info I've got from your post
class Example extends React.Component {
handleClick = () => this.props.removeFunctionsData(this.props.path, this.props.obj.data_type);
render() {
return (
<ComponentToClick onClick={this.handleClick} />
)
}
}
Original answer :
You can execute your function by adding () at the end :
onClick={
(e)=>{
this._onClose(e);
this.props.removeFunctionsData.bind(null,this.props.path,this.props.obj.data_type)();
}
}
Edit : as dschu commented, the above code is pretty bad, binding or using arrow function in the render method is a bad practice because it creates a new function each time.
Binding your function is useless in this case because you pass null as first argument.
To solve the arrow function performance issue in a generic way you have to bind your function in the constructor or declare an arrow method.
Here's a better code to do what you need :
Class MyComponent extends React.Component {
// your other class methods
handleClick = (e) => {
this._onClose(e);
this.props.removeFunctionsData(this.props.path,this.props.obj.data_type);
}
render() {
<div onClick={this.handleClick} />
}
}

I am confused that should I bind fat arrow function or not in ReactJS?

I am confused that should I bind fat arrow function or not in ReactJS?
normal functions does not work properly without binding but I dont know about fat arrow functions should be binded or not
No, you do not need to bind this for arrow functions. They have the same this value as the enclosing context.
this.myValue = 5;
const myFunc = () => {
this.myValue = 10;
}
myFunc();
console.log(this.myValue); // 10
See here for more details.
If your binding function needs this (wich seems mandatory), you effectively need to bind correctly the this. The best way (recommanded by the airbnb eslinter) is the fat arrow function.
As an exemple, let's assume I have this component :
class MyComponent extends React.Component {
toBeRunOnSpanClick() {
this.props.clickHandler();
}
render() {return <span onclick={/* What should you use here*/}></span>}
}
This won't work :
class MyComponent extends React.Component {
toBeRunOnSpanClick() {
this.props.clickHandler();
}
render() {return <span onclick={this.toBeRunOnSpanClick}></span>}
}
The this in your toBeRunOnSpanClick function won't be the same than your class. That is the way javascript works.
The good way will be :
class MyComponent extends React.Component {
toBeRunOnSpanClick() {
this.props.clickHandler();
}
// this.toBeRunOnSpanClick.bind(this) will work too but it is way less comprehensive
render() {return <span onclick={() => {this.toBeRunOnSpanClick()}}></span>}
}

Avoid .bind in ES6(7?) with Babel

I have this in my JSX:
<Options options={options} onOptionSelect={this.onOptionSelect.bind(this)} />
However, I swear I've seen some fanciness to negate the need for .bind when passing callback methods down to child React components, am I right?
You can use an arrow function combined with property initialization.
class Component extends React.Component {
handleClick = () => {
console.log(this.props);
}
render() {
return <div onClick={this.handleClick} />
}
}
Because the arrow function is declared in the scope of the constructor, and because arrow functions maintain this from their declaring scope, it all works. The downside here is that these wont be functions on the prototype, they will all be recreated with each component. However, this isn't much of a downside since bind results in the same thing.
You can bind all the functions of a component using ES2015 class syntax with this autoBind helper function:
class Component extends React.Component {
constructor(props) {
super(props);
autoBind(this);
}
onOptionSelect() {
// do stuff
}
render() {
return <Options options={options} onOptionSelect={this.onOptionSelect} />;
}
}
function autoBind(obj) {
getAllMethods(obj.constructor.prototype)
.forEach(mtd => {
obj[mtd] = obj[mtd].bind(obj);
});
}
function getAllMethods(obj) {
return Object.getOwnPropertyNames(obj).filter(key => typeof obj[key] == "function");
}
Note that Component doesn't have to use methods defined with arrow functions.

Resources