How to setState inside static function React native - reactjs

I want to setState in a static function. But I got an error which says setState is not a function:
export default class SearchTab extends React.Component {
constructor(props) {
super(props);
this.state = {
name: ''
}
}
static callingFun = () => {
this.setState({ name:'ali' })
}
}

You cannot use this.setState in a static method.Because if you use static function then a static method won't be able to access 'this' inside that function. Please refer https://odetocode.com/blogs/scott/archive/2015/02/02/static-members-in-es6.aspx

Statics don't have instances. They are basically shared between classes and this won't work in it. You should make your function a class function instead

Related

How do you access React statics within instance methods?

I'm using React 16.13.0. I have defined this static block within my component ...
class FormContainer extends Component {
statics: {
DEFAULT_COUNTRY: 484;
}
constructor(props) {
super(props);
...
componentDidMount() {
let initialCountries = [];
let initialProvinces = [];
// Get initial countries
fetch('/countries/')
.then(response => {
return response.json();
}).then(data => {
initialCountries = data.map((country) => {
return country
});
console.log("output ...");
console.log(initialCountries);
this.setState({
countries: initialCountries,
});
});
// Get initial provinces (states)
console.log("val:" + this.DEFAULT_COUNTRY);
My question is, how do I reference that static block? The above
console.log("val:" + this.DEFAULT_COUNTRY);
produces
undefined
Confusion comes from old React.createClass function that you would use if your runtime didn't support classes as a Javascript feature. You would pass an object in React.createClass and React would create sort-of-a-class for that component. There, statics property on that object would serve like an object with all static properties of that pseudo class:
// old
const MyComponent = React.createClass({
statics: {
DEFAULT_COUNTRY: 484
},
render: function() {}
})
There is no real class going on here, it's just an object inside an object, and it is indeed easy to confuse with e.g. static block in Java
With ES6 classes (which you are using) static properties are declared like this
class MyComponent extends React.Component {
static DEFAULT_COUNTRY = 484
static ANOTHER_STATIC_PROPERTY = 23
render () {}
}
And can be accessed as MyComponent.DEFAULT_COUNTRY anywhere
You are most likely using Babel, in that case, babel-plugin-proposal-class-properties should be enabled, as not all browsers support this feature. Node without Babel supports class properties from version 12
There are no static blocks in Javascript per se, but you can modify the class from static context from outside, e.g.
class MyComponent extends React.Component {
static DEFAULT_COUNTRY = 484
static ANOTHER_STATIC_PROPERTY = 23
render () {}
}
MyComponent.HELLO = 'world'
Let’s use:
static DEFAULT_COUNTRY = 484
With static you can assign a property/method to the class function itself, not to its prototype. The value of this in FormContainer.DEFAULT_COUNTRY is the class constructor FormContainer itself.
You can access it from within the class as this.constructor.DEFAULT_COUNTRY. And as FormContainer.DEFAULT_COUNTRY within the class and out of it.
So, console.log("val:" + this.constructor.DEFAULT_COUNTRY);
Consider the following as an options to store DEFAULT_COUNTRY`:
class FormContainer extends Component {
constructor(props) {
super(props);
this.DEFAULT_COUNTRY = 484;
}
render(){
console.log(this.DEFAULT_COUNTRY)
...
}
};
or
class FormContainer extends Component {
DEFAULT_COUNTRY = 484;
render(){
console.log(this.DEFAULT_COUNTRY)
...
}
};
or, this could be also an option:
class FormContainer extends Component {
statics = {
DEFAULT_COUNTRY: 484,
};
render(){
console.log(this.statics.DEFAULT_COUNTRY)
...
}
};
But in the last example, statics is not key word, but just a name of class field. Hope this will help you.
Actually the declaration has an issue, you should use below code:
class FormContainer extends Component {
statics = { // use equal sign not colon sign
DEFAULT_COUNTRY: 484, // use comma here not semicolon
};
Then in everywhere of FormContainer class, you can access by this.statics, for your default country you can access by this.statics.DEFAULT_COUNTRY.
By using the colon for declaring the statics variable of the class, you just get undefined.
Hint: do not use static keyword. it defines a static variable for the class that is not accessible inside the class. in ReactJS the static keyword often use for declaring prop types of class props members.
Update
To prove this correctness of code: see the IDE and the Browser
If you got an error, please show your code, maybe you call it in an irrelevant place.

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.

Assinging value to variable outside class

I am accessing JSON file in ComponentDidMount in class A, i need to access that result outside class and need to use that in Class B
let test;
console.log(test);
class CustomerPage extends React.Component {
componentDidMount(): void {
$.getJSON("/api/LocaleStrings")
.done(results => {
let JsonString = JSON.parse(results);
test = new LocalizedStrings(JsonString);
})
.fail(console.log.bind(console));
}
}
Here, console.log(test) yields undefined.
It seems to me that your console.log(test) gets executed before the AJAX call returns, and at that point it will be uninitialized (undefined). Place your console.log inside the done function.
You could store your AJAX result in your component's state:
class CustomerPage extends React.Component {
constructor(props) {
super(props);
this.state = { test: null };
}
componentDidMount(): void {
$.getJSON("/api/LocaleStrings")
.done(results => {
let JsonString = JSON.parse(results);
this.setState({
test: new LocalizedStrings(JsonString);
});
})
.fail(console.log.bind(console));
}
}
You need to have an "event" that notifies anyone who is interested that test is available:
interface CustomerPageProps {
onLocaleStringsLoaded?: (test:object) => void
}
class CustomerPage extends React.Component<CustomerPageProps> {
static defaultProps {
onLocaleStringsLoaded: () => {} //nothing by default
}
componentDidMount(): void {
$.getJSON("/api/LocaleStrings")
.done(results => {
let JsonString = JSON.parse(results);
const test = new LocalizedStrings(JsonString);
this.props.onLocaleStringsLoaded(test);
}).fail(console.log.bind(console));
}
}
Then at some point in your code you could have:
<CustomerPage onLocaleStringsLoaded={window.console.log.bind(window.console)} />
which will print to the console once the result is available.
I recommend reading up a bit more on how React components share data. The component that needs the data can have an input defined, in which you can pass the test variable. Or using a redux store (which could potentially be a little too complex for your application). If you really want to continue this route. You can always use the window object to set a global variable: window.test = 'bla';. This is available anywhere in the application with console.log(window.test);.
You would have to update your code to:
window.test = new LocalizedStrings(JsonString);.
Verifying that it is set can be done with an interval:
setInterval(function() {
console.log(window.test);
}, 100);

Is the constructor still needed in React with autobinding and property initializers

I am refactoring an es6 class based React component that uses the normal constructor, and then binds methods, and defines state/attributes within that constructor. Something like this:
class MySpecialComponent extends React.Component {
constructor(props) {
super(props)
this.state = { thing: true }
this.myMethod = this.myMethod.bind(this)
this.myAttribute = { amazing: false }
}
myMethod(e) {
this.setState({ thing: e.target.value })
}
}
I want to refactor this so that I am autobinding the functions, and using property initializers for the state and attributes. Now my code looks something like this:
class MySpecialComponent extends React.Component {
state = { thing: true }
myAttribute = { amazing: false }
myMethod = (e) => {
this.setState({ thing: e.target.value })
}
}
My question is, do I still need the constructor? Or are the props also autobound? I would have expected to still need the constructor and included super(props), but my code seems to be working and I'm confused.
Thanks
From my understanding, you don't need to type out a constructor at all when using class properties (as in your second code example). The accepted answer states that you do need one if you "need to reference the props in your initial state object," but if you're using said class properties, then you're probably using Babel to transpile it, in which case a constructor is used, it's just being done behind the scenes. Because of this, you don't need to add a constructor yourself, even if you are using props in state.
See this aricle for better examples and a better explanation.
You don't need an explicitly defined constructor unless you need to reference the props in your initial state object.
You don't need to define a constructor explicitly , and then do super(props).You can access the props as in the example below. i.e. 'prop1'
class MySpecialComponent extends React.Component {
state = {
thing: true ,
prop1:this.props.prop1
}
myAttribute = { amazing: false }
myMethod = (e) => {
this.setState({ thing: e.target.value })
}
render(){
console.log(this.state.prop1);
return(
<div>Hi</div>
);
}
}
ReactDOM.render(<MySpecialComponent prop1={1}/> , mountNode);

How to properly use arrows for ES6 React class functions? [duplicate]

I'm new to using ES6 classes with React, previously I've been binding my methods to the current object (show in first example), but does ES6 allow me to permanently bind a class function to a class instance with arrows? (Useful when passing as a callback function.) I get errors when I try to use them as you can with CoffeeScript:
class SomeClass extends React.Component {
// Instead of this
constructor(){
this.handleInputChange = this.handleInputChange.bind(this)
}
// Can I somehow do this? Am i just getting the syntax wrong?
handleInputChange (val) => {
console.log('selectionMade: ', val);
}
So that if I were to pass SomeClass.handleInputChange to, for instance setTimeout, it would be scoped to the class instance, and not the window object.
Your syntax is slightly off, just missing an equals sign after the property name.
class SomeClass extends React.Component {
handleInputChange = (val) => {
console.log('selectionMade: ', val);
}
}
This is an experimental feature. You will need to enable experimental features in Babel to get this to compile. Here is a demo with experimental enabled.
To use experimental features in babel you can install the relevant plugin from here. For this specific feature, you need the transform-class-properties plugin:
{
"plugins": [
"transform-class-properties"
]
}
You can read more about the proposal for Class Fields and Static Properties here
No, if you want to create bound, instance-specific methods you will have to do that in the constructor. However, you can use arrow functions for that, instead of using .bind on a prototype method:
class SomeClass extends React.Component {
constructor() {
super();
this.handleInputChange = (val) => {
console.log('selectionMade: ', val, this);
};
…
}
}
There is an proposal which might allow you to omit the constructor() and directly put the assignment in the class scope with the same functionality, but I wouldn't recommend to use that as it's highly experimental.
Alternatively, you can always use .bind, which allows you to declare the method on the prototype and then bind it to the instance in the constructor. This approach has greater flexibility as it allows modifying the method from the outside of your class.
class SomeClass extends React.Component {
constructor() {
super();
this.handleInputChange = this.handleInputChange.bind(this);
…
}
handleInputChange(val) {
console.log('selectionMade: ', val, this);
}
}
You are using arrow function and also binding it in constructor. So you no need to do binding when you use arrow functions
class SomeClass extends React.Component {
handleInputChange = (val) => {
console.log('selectionMade: ', val);
}
}
OR you need to bind a function only in constructor when you use normal function like below
class SomeClass extends React.Component {
constructor(props){
super(props);
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(val){
console.log('selectionMade: ', val);
}
}
Also binding a function directly in render is not recommended. It should always be in constructor
I know this question has been sufficiently answered, but I just have a small contribution to make (for those who don't want to use the experimental feature). Because of the problem of having to bind multiple function binds in the constructor and making it look messy, I came up with a utility method that once bound and called in the constructor, does all the necessary method bindings for you automatically.
Assume I have this class with the constructor:
//src/components/PetEditor.jsx
import React from 'react';
class PetEditor extends React.Component {
constructor(props){
super(props);
this.state = props.currentPet || {tags:[], photoUrls: []};
this.tagInput = null;
this.htmlNode = null;
this.removeTag = this.removeTag.bind(this);
this.handleChange = this.handleChange.bind(this);
this.modifyState = this.modifyState.bind(this);
this.handleKeyUp = this.handleKeyUp.bind(this);
this.addTag = this.addTag.bind(this);
this.removeTag = this.removeTag.bind(this);
this.savePet = this.savePet.bind(this);
this.addPhotoInput = this.addPhotoInput.bind(this);
this.handleSelect = this.handleSelect.bind(this);
}
// ... actual method declarations omitted
}
It looks messy, doesn't it?
Now I created this utility method
//src/utils/index.js
/**
* NB: to use this method, you need to bind it to the object instance calling it
*/
export function bindMethodsToSelf(objClass, otherMethodsToIgnore=[]){
const self = this;
Object.getOwnPropertyNames(objClass.prototype)
.forEach(method => {
//skip constructor, render and any overrides of lifecycle methods
if(method.startsWith('component')
|| method==='constructor'
|| method==='render') return;
//any other methods you don't want bound to self
if(otherMethodsToIgnore.indexOf(method)>-1) return;
//bind all other methods to class instance
self[method] = self[method].bind(self);
});
}
All I now need to do is import that utility, and add a call to my constructor, and I don't need to bind each new method in the constructor anymore.
New constructor now looks clean, like this:
//src/components/PetEditor.jsx
import React from 'react';
import { bindMethodsToSelf } from '../utils';
class PetEditor extends React.Component {
constructor(props){
super(props);
this.state = props.currentPet || {tags:[], photoUrls: []};
this.tagInput = null;
this.htmlNode = null;
bindMethodsToSelf.bind(this)(PetEditor);
}
// ...
}

Resources