React binding through constructor - possible to automate? - reactjs

As per recommendations from others, I have been binding class methods in the constructor in React, for example:
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
I have components with many methods, and I am binding all of these methods to this. Argh, what a pain! To avoid repetitively maintaining this pattern, I built a function that would be called in the constructor in place of all the individual calls; it binds all the methods specific to that class, while a parent class would take care of its own methods moving up the classes. For example:
function bindClassMethodsToThis(classPrototype, obj) {
Object.getOwnPropertyNames(classPrototype).forEach(prop => {
if (obj[prop] instanceof Function && prop !== 'constructor') {
obj[prop] = obj[prop].bind(obj);
console.log(`${classPrototype.constructor.name} class binding ${prop} to object`);
}
});
}
class A {
constructor() {
bindClassMethodsToThis(A.prototype, this);
}
cat() {
console.log('cat method');
}
}
class B extends A {
constructor() {
super();
bindClassMethodsToThis(B.prototype, this);
}
dog() {
console.log('dog method');
}
}
let b = new B();
So, React and ES6 gurus, is this a reasonable approach, or I am doing something wrong here? Should I stick to the individual bindings to this?

Your strategy seems sound, though there are some edge cases that you may end up wanting to tackle. A library like react-autobind, which Alexander mentioned, takes care of some of these things for you, and if I were to use this strategy I would probably use a library like this one (or take a look into the source code to get an idea for what it does).
For completeness, some alternative approaches are:
Use class properties and arrow functions (along with any necessary Babel transforms) to create pre-bound methods:
class MyComponent extends React.Component {
handleChange = () => { /* ... */ }
}
Use a decorator, like the autobind decorator from core-decorators, along with any necessary Babel transforms (this was the strategy I used previously):
import { autobind } from 'core-decorators'
class MyComponent extends React.Component {
#autobind
handleChange() { /* ... */ }
}
Explore the use of Hooks (currently in alpha) to avoid the problem of binding all together (since state values and setters exists as local variables to be closed over). This is the strategy I've been preferring very recently, but please note it is still in the proposal state and may change. :)

Assuming you have Babel setup for it, you can also use arrow functions instead, avoiding the need to bind this:
class Foo extends React.Component {
handleClick = (event) => {
event.preventDefault()
}
render() {
return <div onClick={this.handleClick}>Click me</div>
}
}

One way to resolve this is to call bind in render:
onChange={this.handleChange.bind(this)}

Related

Defining my function inside or outside the class

So, this is just a best practices question.
If I have a create class like:
class Example extends Component {
method = () => {
return 'hello';
}
}
Versus:
methodFunction() {
return 'hello';
}
class Example extends Component {
method = () => {
return methodFunction;
}
}
What are the major differences? I get that if I need access to this, I won't have it in the methodFunction unless I pass it in. But, are there any other scope related gotchas to moving my functions outside of the class?
Also, I'm curious because, I'd like to move all the functions outside of the class. Seems like it would be easier to test functions this way.
Let me know what you think,
Cheers!

Why do some developers use constructor and super in their class in React.js?

I always use this expression in my components:
class Cart extends Component { }
Recently I have seen a lot of codes using this expression.
class Cart extends React.Component {
constructor(props) {
super(props);
}
}
Why is it? What is the purpose of using constructor and super?
Is React.Component and Component same?
Why do we pass props in constructor and super?
I am not asking what super and constructor are, I am asking difference between 2 codes above and benefits of using each one?
I checked online but did not see any explanation, just code examples.
Constructors and super are not react specific or even javascript specific. They are specific to the inheritance in OOP.
Constructors
Constructors are what can be called as initializing functions in a class. Let's look at an example where a constructor can be used.
class parentClass {
constructor(){
this.foo = foo;
this.bar = bar;
}
function sharedMethod1(){
print(this.foo);
}
function sharedMethod(){
print(this.bar)
}
}
object1 = new ParentClass(foo1, bar1);
object1.sharedMethod1() // this will print foo1;
object1.sharedMethod2() // this will print bar1;
object2 = new ParentClass(foo2, bar2);
object2.sharedMethod1() // this will print foo2;
object2.sharedMethod2() // this will print bar2;
when there is a need to create multiple instances of a class with different values for member variables / functions, we make use of the constructor functions.
Super
The super keyword is used in inheritance as well. In inheritance when extending a child class from a parent class, there is a need to initialise the constructor of the parent class. The super keyword is used for this purpose. let's look at the below example for super.
class ParentClass (){
constructor(){
this.foo = foo;
}
}
class childClass extends ParentClass(){
super(foo1); // super is used here initialize the constructor of the ParentClass
}
The same principle mentioned above is followed in React as well.
Please look into dan abramov's blog post on constructor and super here https://overreacted.io/why-do-we-write-super-props/
Dan Abramov mentions on his blog that:
You can’t use this in a constructor until after you’ve
called the parent constructor.
JavaScript won’t let you.
JavaScript enforces that if you want to use this in a constructor, you
have to call super first.
calling super(props) is needed in order to access this.props.
as mentioned on this thread, there are 2 main reasons to use a constructor on a react component:
Initializing local state by assigning an object to this.state.
Binding
event handler methods to an instance.
If you don’t initialize state and you don’t bind methods, you don’t need to implement a constructor for your React component.
If you don’t initialize state and you don’t bind methods, you don’t
need to implement a constructor for your React component.
Copied from reactJS website.
If you don’t initialize state and you don’t bind methods, you don’t
need to implement a constructor for your React component.
The constructor for a React component is called before it is mounted.
When implementing the constructor for a React.Component subclass, you
should call super(props) before any other statement. Otherwise,
this.props will be undefined in the constructor, which can lead to
bugs.
Typically, in React constructors are only used for two purposes:
Initializing local state by assigning an object to this.state.
Binding event handler methods to an instance.
You should not call setState() in the constructor(). Instead, if your
component needs to use local state, assign the initial state to
this.state directly in the constructor:
Constructor is the only place where you should assign this.state
directly. In all other methods, you need to use this.setState()
instead.
Avoid introducing any side-effects or subscriptions in the
constructor. For those use cases, use componentDidMount() instead.
https://reactjs.org/docs/react-component.html
And here is the purpose of super() ,
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super
I tried with babel, Here's what I get.
With Constructor I get this function,
class App extends React.Component{
constructor(props){
this.state = {}
}
}
Related part in ES5,
var App =
/*#__PURE__*/
function (_React$Component) {
_inherits(App, _React$Component);
function App(props) {
var _this;
_classCallCheck(this, App);
_this.state = {};
return _possibleConstructorReturn(_this);
}
return App;
}(React.Component);
Without Constructor
class App extends React.Component{
state = {}
}
ES5 code
var App =
/*#__PURE__*/
function (_React$Component) {
_inherits(App, _React$Component);
function App() {
var _getPrototypeOf2;
var _temp, _this;
_classCallCheck(this, App);
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _possibleConstructorReturn(_this, (_temp = _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(App)).call.apply(_getPrototypeOf2, [this].concat(args))), _this.state = {}, _temp));
}
return App;
}(React.Component);
Why is it? What is the purpose of using constructor and super?
Constructors and the super-keyword are not react specific, but JavaScript specific. Search for inheritance and "OOP" in JavaScript to better understand it (e.g. this medium article). super and inheritance is also not only bound to JavaScript, many other languages also use it and explain it accordingly, here for example is a good explanation of how the super-keyword should be used in java.
Why do we pass props in constructor and super?
Check Why Do We Write super(props)?.
Is React.Component and Component same?
Yes. In the head-section of the files are a bunch of import ...-statements. For React.Component you will find something like import * as React from "react" or import React from "react". In case of Component you will find import { Component } from "react". Check the import-documentation from MDN for more information.
I am asking difference between 2 codes above and benefits of using each one?
There is no difference in the result. Both versions work the same and there is no (notable) difference in performance. One version is shorter and less noisy. If you have no further instructions in the constructor, I would recommend suppressing it.

mobx react action binding

For those who has written apps with mobx + react, I'm wondering if there's a better way to handle context issue (eg. this. returns undefined in mobx store) when using onClick event handler inside a react component w/ inject & observer.
I have been writing the handler like onClick={actionFromStore.bind(this.props.theStore)} to resolve that issue, but it seems like there should be more concise way to do this that I'm not aware of.
I'm not a mobx expert, any advice would be appreciated!
The actions here are async fetch requests
You can either use #action.bound decorator:
#action.bound
doSomething(){
// logic
}
or use labmda function which will preserve the context:
#action
doSomething = ()=> {
// logic
}
Since there is 2018, the best practice in React apps development is to use lambda functions as class properties instead of class methods.
The lambda function as class property resolves all issues that can happen with context. You don't have to bind methods to the specific context, if using it.
For example, you working with this in some class method:
export default class SomeClass {
myProp = "kappa"
myMethod() {
console.log(this.myProp)
}
}
In this case, if you will use it, e.g., like some event listener, this will be unexpectedly (actually, more than expected) change from SomeClass instance to other value. So, if you using class methods, you should modify you code like this:
export default class SomeClass {
constructor() {
this.myMethod = this.myMethod.bind(this)
}
myProp = "kappa"
myMethod() {
console.log(this.myProp)
}
}
In constructor you are binding your class method to context of SomeClass instance.
The best way to avoid this kind of unnecessary code (imagine, that you have 10+ of this type of methods - and you should bind each of them), is to simply use lambda functions:
export default class SomeClass {
myProp = "kappa"
myMethod = () => {
console.log(this.myProp)
}
}
That's it! Lambda functions have no context, so this will always point to the SomeClass instance. So, now you can decorate you class property as you wish:
export default class SomeClass {
myProp = "kappa"
#action
myMethod = () => {
console.log(this.myProp)
}
}
Note, that if you are using Babel, you have to use transform-class-properties plugin.
This question is more related to the core of JavaScript, so I advise you to read this MDN article for more information about this behavior.
Hope, this was helpful!
With Mobx 6, decorators are becoming more discouraged and cumbersome to use (requiring makeObservable(this) to be called carefully in the constructor, even in subclasses.)
I therefore now find it cleaner to use
doStuff = action(() => {
// stuff logic
})
rather than
#action.bound
doStuff() { ...
or
#action
doStuff = () => { ...
This pattern with no decorators also works in older Mobx versions.

Should class methods be created with arrow functions

When creating React components I sometimes on the web that methods are created with arrow function syntax, and sometimes without it. E.g.
class Component extends .... {
someFnk = (param) => { ... }
}
vs
class Component extends .... { someFnk(param) { ... } }
Which approach is better practice? Arrow function makes is safe to use this in function body, however I wonder when in React this could be an issue (when this could change)?
To rephrase the question: when arrow function syntax can safe me from creating a bug?
As long as you bind class methods in the constructor, the final, overall output is the same.
The following, once compiled operate in an identical manner.
class Foo extends React.Component {
constructor(props) {
super(props)
this.handleBla = this.handleBla.bind(this)
}
handleBla() {
}
}
class Foo extends React.Component {
handleBla = () => {
}
}
You say "why bind this when in React this won't change". That isn't actually true - all event handlers change the context of this. So make sure to either use the arrow function or bind for event handlers.
Transpiled
Once you transpile both through babel, you can see there is very little difference. The arrow function is simply mapped onto _this (remember this technique from pre-ES6 days?)
var Foo = function () {
function Foo() {
_classCallCheck(this, Foo);
this.handleBla = this.handleBla.bind(this);
}
_createClass(Foo, [{
key: "handleBla",
value: function handleBla() {
console.log(this);
}
}]);
return Foo;
}();
var Foo = function Foo() {
var _this = this;
_classCallCheck(this, Foo2);
this.handleBla = function () {
console.log(_this);
};
};
Summary:
It's basically the same, but you must use bind context (either via the arrow function or bind) if you intend to use them with events and reference the component. This extremely common as most event handlers refer to state, setState or props, and so you will need the correct this

bind(this) in ReactComponent.render() method

I have a quite big React.Component with more than ten bind(this) calls in its constructor.
I don't think .bind(this) in a constructor gives any help to understand my code especially when reading the code inside of render().
So, I came up with the following idea, however, do not find how to achieve this.
render() {
if (this.methodToBind.getThis() === this) {
this.methodToBind = this.methodToBind.bind(this);
}
}
Is there any possible way I can get this of a method (getThis() from the example above)?
If yes for the above, is it a good practice to do this?
rather then doing this,
constructor () {
super();
this.myFunc = this.myFunc.bind(this);
}
myFunc () {
// code here
}
You can do something like this.
constructor () {
super();
// leave the binding, it's just not what the cool kids do these days
}
myFunc = () => {
// see what I did here with = () => {}
// this will bind your `this` with it's parent
// lexical context, which is your class itself, cool right. Do this!
}
For a reference have a look at the MDN documentation for Arrow Functions
Where to Bind This?
When you create a function in a Class Based Component in React.js you must bind this in order to call it from the render method. Otherwise the function will not be in scope.
There are a few ways to do this.
Never bind this in the render method. Binding this in the render method will cause React to create a new function every time your Component is rerendered. This is why we most commonly bind in the constructor.
Bind in the constructor. By binding in the constructor, you can call your function in the render method by using this.FunctionName();
Example Bind This
Class MyClass extends Component {
constructor(props) {
super(props);
this.FunctionName = this.FunctionName.bind(this);
}
myFunc () {
// code here
}
render() {
this.FunctionName();
return(
<div>
...
</div>
);
}
}
User fat arrow functions instead of traditional function definitions. Fat arrow functions lexically bind the this value. So you do not have to add bind to the function in the constructor when you use the fat arrow function in the class.
Important - Fat arrow functions are not always available to use in a React class. Depending on how you setup React. You might have to install,
babel-plugin-transform-class-properties
Then add it to your .bablerc file like this,
{
"plugins": [
"transform-class-properties"
],
"presets": [
"react"
]
}
Example Fat Arrow
Class MyClass extends Component {
myFunc = () => {
// code here
}
render() {
this.FunctionName();
return(
<div>
...
</div>
);
}
}
Summary
Never bind a function in the render.
Always bind in the constructor when using a traditional function
this is automatically available on the function when using a fat arrow function.
Not sure.
I am usually doing something like this:
onClick={this.handleClick.bind(this)}
or:
onClick={e => this.handleClick(e)}

Resources