How to migrate getter function in class based component to functional component? - reactjs

I'm trying to migrate my class based component to functional component.
keep getting struggles on change getter / static methods , how can I achieve these?
// class based component
class Example extends Component {
...
flag = Math.random * 1 + 1;
get someGetter(){
return flag
}
usingGetter(){
if(this.someGetter) console.log("using Getter called! ");
}
static someStatic(){
console.log("this is some static function" );
}
...
}

just convert it to normal variable, you dont need it as class member
const someGetter = () => flag
usingGetter () {
if (someGetter()) console.log("using Getter called! ");
}

Related

How can i call static variables from outside of my Component?

I want to create my static variables outside of my component and then call and using it in my component.
Btw i dont want outside variables as a component or props.
You can create class like that
export default class TableConst {
static LocaleText = {
values: {
to: "-",
page: " ",
}
};
}
Then import that static class and use it in your main page
import TableConst from "../TableConst";
...
...
...
let columnDefs={TableConst.LocaleText.values}
If you define variable inside the class using a static keyword you can access those variable using class Name directly without instantiating it.
class CustomVariables {
static MyVariable = 'SomeContent';
static MyVariable2 = 'SomeContent2';
}
export default CustomVariables;
Also you could write those variables within the class and return an instance of the class
class CustomVariables {
constructor() {
this.MyVariable = 'SomeContent';
this.MyVariable2 = 'SomeContent2';
}
}
export default CustomVariables();
and you can use it like below for both the caes
import CustomVariables from 'path/to/CustomVariables';
console.log(CustomVariables.MyVariable)

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.

React binding through constructor - possible to automate?

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

Reactjs → static methods without access to "this", what's the alternative?

EDITED: Static methods don't have access to "this". The underlying question is then, how in reactjs should you organize the code, if you'd like to separate functionalities in different classes? the only way to call the methods of these classes is then by making them "static". Is it really the only way? What are you supposed to do? Create one big class so that all methods will have access to "this"?
EDITED2: What I have done is then to avoid writing a static method that needs to have access to the state. In particular, I've used a promise to return the value to the class that does have access to the state.
static Parse(cvs_string) {
return new Promise((resolve, reject) => {
Papa.parse(cvs_string, {
header: true,
skipEmptyLines: true,
complete: (results) => resolve(results)
});
});
}
EDITED3: But, as said in the comments, it's nonesense to build a class that also extends from Component if the main reason is to provide helper functions, so at the end:
import Papa from 'papaparse';
export const ParseCsv = (csv_string) => {
return new Promise((resolve, reject) => {
Papa.parse(csv_string, {
header: true,
skipEmptyLines: true,
complete: (results) => resolve(results)
});
});
}
---- [previous]
Why is this not working? Shouldn't I have access to setstate here?
import React, { Component } from 'react';
import Papa from 'papaparse';
class PapaParse extends Component {
constructor(props) {
super(props);
this.Parse = this.Parse.bind(this);
this.updateData = this.updateData.bind(this);
}
static Parse(cvs_string) {
Papa.parse(cvs_string, {
header: true,
skipEmptyLines: true,
// complete: (results) => { // this gives the same error
complete: function(results) {
PapaParse.updateData(results);
}
});
}
static updateData(results) {
console.log(results); // results are the expected ones
PapaParse.setState({data: results.data}); // here the error, or
this.setState({data: results.data}); // here the same error
}
}
export default PapaParse;
I can solve this by sending "this" as a variable, in
PapaParse.Parse(response, this);
and then in the PapaParse component
static Parse(cvs_string, that) {
...
PapaParse.updateData(results, that);
...
static updateData(results, that) {
...
that.setState({data: results.data});
So I understand that the "this" is lost when I'm calling a method of a componenet without invoking it with the "tag", and merely calling it as a static method.
Then, what I'm doing here is what I'm supposed to do? Or what would be the best way to do this?
Static methods are intended for code that doesn't depend on class instance, because there's none. There are not so many good use cases for static methods, because if a function isn't directly linked to a class as an entity, it possibly doesn't need to be a part of it. One of use cases is React component getDerivedStateFromProps hook which is pure function that needs to defined as a method (because it's a hook that should be accessed as class property by the framework), it forces a developer to not use class instance and focus on function input and output.
Since the method needs class instance and setState instance method in particular, static methods are not applicable here. None of these methods should be static:
class PapaParse extends Component {
Parse(cvs_string) {
Papa.parse(cvs_string, {
header: true,
skipEmptyLines: true,
complete: (results) => {
this.updateData(results);
}
});
}
updateData(results) {
console.log(results);
this.setState({data: results.data});
}
}
This is same problem as explained in this answer:
this.Parse = this.Parse.bind(this);
It's a mistake to bind static method to class instance, especially in a class that isn't a singleton by design and is expected to be instantiated multiple times (React component class is). There can be multiple class instances, this may result in bugs and memory leaks.
If Parse method is supposed to be triggered outside this class, this should be done in a way that is idiomatic to React, e.g. get PapaParse component ref in parent component and access instance method on it:
// in constructor
this.papaParseRef = React.createRef();
...
// in render
<PapaParse ref={this.papaParseRef}/>
The method will be available as this.papaParseRef.current.Parse() after render.
PapaParse.setState({data: results.data}); // here the error
Should be this.setState so you reference the instance, not the class.
Declare updatedata() as an arrow function.
updatedata=(results) => {
//this.setState will work here
}

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

Resources