React call function from another function in a loop - reactjs

I am writing a React class and trying to call a function form another function but in a for loop, I am getting this error
Uncaught ReferenceError: isValidated is not defined
If I move my function call out of for each loop, it work fine. I am using arrow function, so I believe I don;t need binding in constructor.
class ResourceManagerForm extends React.Component {
render() {
return (<button className="ms-Button ms-Button--primary" onClick={this.onSaveButtonClick}>
<span className="ms-Button-label">Create Account name</span>
</button>)
}
isValidated = (control) =>
{
//some code here
}
onSaveButtonClick = (e) =>
{
this.isValidated(null); //works fine here
$("#resource-manager [id]").each(function (index, value)
{
if(isValidated(value)) //does not work
{
}
if(this.isValidated(value)) //also does not work
{
}
});
}
}

It's because of how you define the anonymous function in .each()
For this to be bound inside the function, you need to declare it as an "arrow" function i.e. (index, value) => { ... } instead of function(index, value) { ... }:
this.isValidated(null); //works fine here
$("#resource-manager [id]").each((index, value) => {
if(this.isValidated(value)) { // this is bound inside the function now
}
});
This blog post explains how arrow functions behave.

Related

Unhandled Rejection (TypeError): this is undefined

Getting this is undefined error. Tried searching for solution but didn't find any.
This same code is working fine on another page but don't know what's wrong here. Printing output of brands before setState is printing valid result.
class FindSponsors extends Component {
constructor() {
super();
this.state = {
data: []
}
}
componentDidMount() {
db.ref("sponsor").once("value").then(function (snapshot) {
let data = snapshot.val()
let brands = []
for (let brand in data) {
brands.push({
name: data[brand].Name,
website: data[brand].Website
})
}
this.setState({ //Error here
data: brands
})
});
}
render() {
return (
<div className="main">
</div>
);
}
}
export default FindSponsors;
Try using the arrow function:
db.ref("sponsor").once("value").then((snapshot) => { /*your function body here*/})
this keyword is nothing more than a link to an execution context. In your example above you "execute" function "in the callback".
Try reading this to understand better how it works and how arrows functions are different from regular ones.
The problem here is that when you define your callback function in the .then, the context of this function changes and this will basically refer to the inside of the function.
Two solutions here:
Use the .bind method to change the value of this for your callback. It would be something like this:
const callback = function (snapshot) {
// Your callback logic
}
db.ref("sponsor").once("value").then(callback.bind(this));
Use an arrow function. They have the specificity to not have their own bindings of the this keyword. This would be like this:
db.ref("sponsor").once("value").then((snapshot) => {
// Your callback logic
});

Cannot read property 'someFunction' of null for 'someFunction' within onClick

I am rendering a list of items retrieved from Firebase. For each item, I render a div, that includes a button that removes said item.
Relevant code:
constructor(props){
// Pass props to parent class
super(props);
this.removeItem = this.removeItem.bind(this);
this.getList = this.getList.bind(this);
...
}
removeItem(key) {
this.ref(key).remove()
}
getList() {
var list = []
this.ref.on("value", function (snapshot) {
for (var key in snapshot.val()) {
list.push(<div class="todo-item">{snapshot.val()[key]} <button onClick={() => this.removeItem(key)}> X </button> </div>)
}
}, function (error) {
console.log("Error: " + error.code);
});
return(list)
}
render() {
return (
<div class="todolist">
.....
{this.getList()}
</div>
)
}
The list of items and their remove buttons renders fine. However, when clicking the remove button, I get a TypeError: Cannot read property 'removeItem' of null
As removeItem is a function of this, I assume that this is not properly bound and thus null.
However, I bound both functions removeItem and getList in the constructor.
Does someone know where I am going wrong?
This is the most common problem of context being lost when this is accessed from anonymous function.
To get around this,
Use arrow functions:
this.ref.on("value", (snapshot) => { ... }, (error) => { ... });
OR
Use bind(this)
this.ref.on("value", function (snapshot) { ... }.bind(this), function (error) { ... }.bind(this));

How could i change my state from getCellActions

I am new in react. For my project i want to change my state by clicking an icon from table which will change my state. I am using getCellActions (react-data-grid). How could I pass my custom function alone with column and row object.
Thanks in advance.
NT: I am not using redux
getCellActions(column, row, state) {
if(column.key === 'modify'){
return [
{
icon: 'fa fa-edit',
callback: () => {
console.log(row.id);
//this.getRoleData();
}
}
];
}
}
You can simply use ES6 and pass an arrow function expression that simply invokes the function you want and binds the function with this automatically..
In react-data-grid, you would have to do something like below:
<ReactDataGrid
columns={this._columns}
rowGetter={this.rowGetter}
rowsCount={this._rows.length}
minHeight={300}
getCellActions= {(column, row) => this.getCellActions(column, row)}
state = {this.state}
/>
And your getCellActions function can be as it is:
getCellActions(column, row) {
if(column.key === 'modify'){
return [
{
icon: 'fa fa-edit',
callback: () => this.getRoleData(row.id)
}
];
}
}
The thing is that when you write:
getCellActions= {(column,row) => this.getCellActions(column, row)}
you actually pass an anonymous function which will only be executed when triggered.
I would like to add that when you write an arrow function in one line, it automatically returns that statement, except you wrap that line in curly braces and write a normal function. So, the above line works as :
getCellActions= {(column,row) => return this.getCellActions(column, row)}
So, the MANTRA is: return the reference, do not execute it before the trigger.
The problem why this.getRoleData() is not working, is because this inside of your callback is not in the context of your component.
Change your getCellActions function to an arrow function, so you have the component as context (inside a arrow function this keeps its meaning from its original context):
import React from 'react';
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedRowId: null
};
}
myCallback = (rowId) => {
console.log(rowId);
this.setState({ selectedRowId: rowId });
};
getCellActions = (column, row, state) => {
if(column.key === 'modify'){
return [
{
icon: 'fa fa-edit',
callback: () => {
console.log(row.id);
this.myCallback(row.id);
}
}
];
}
}
render() {
// your render function...
}
}
Alternative:
Bind this to getCellActions in the constructor like:
this.getCellActions = this.getCellActions.bind(this);

how to mixin react class arrow function

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..

Should one use const when declaring an arrow function in React class

Inside a react class component, should one use a const/let to declare an arrow function, or they should be emmited:
class ReactComp extend Component {
const sayHello = () => {
return 'Hello';
}
sayBye = () => {
return 'Hello';
}
render() {
<div>
{this.sayHello}
{this.sayBye}
</div>
}
}
In this example, is sayBye declared correctly? (Without a const)
In addition, why outside the class, such a declaration does not work?
class ReactComp extend Component {
render() {
<div>
{sayHello}
{sayBye}
</div>
}
}
const sayHello = () => {
return 'Hello';
}
sayBye = () => {
return 'Hello';
}
This will return an exception: Uncaught ReferenceError: sayBye is not defined
Thanks a lot!
The answer is "it depends"... your two examples do very different things. Let's take a look at both before I give you a more detailed answer.
class ReactComp extend Component {
const sayHello = () => {
return 'Hello';
}
sayBye = () => {
return 'Hello';
}
render() {
<div>
{this.sayHello}
{this.sayBye}
</div>
}
}
The code above probably throws a syntax error as const (in this context) is not a valid decorator. Even if it was valid (or you simply omit it), sayHello() becomes a method on the ReactComp class (i.e. an instance method). Every time you create a new instance of this component, it will have an internal method called sayHello.
const example = <ReactComp />;
example.sayHello(); // oversimplified example
Make sense? On to your next example:
class ReactComp extend Component {
render() {
<div>
{sayHello}
{sayBye}
</div>
}
}
const sayHello = () => {
return 'Hello';
}
sayBye = () => {
return 'Hello';
}
Ignoring for a moment the syntax error you mentioned earlier, this code creates two global(ish) functions: sayHello() and sayBye() which (depending on your other code) could be accessed globally by any other component or script.
sayHello(); // I can run this line of code anywhere!
// no need for "const example = <ReactComp /> because sayHello() was defined outside of that class
My point: instance methods on a class are different than functions declared outside of a component.
Should one use const when declaring an arrow function in React class?
If you're creating an instance method, then no you don't need const. If you're creating a generic (i.e. utility) function outside of a component, then yes you probably should use const.
You can't define a variable using any declarative statement inside a class.
It expects property names to be attached to the this context of your class.
Defining the following class:
class C extends Component {
sayGoodBye = () => console.log("Bye!")
sayHello = who => console.log("Hello " + who)
render() {
this.sayGoodBye()
this.sayHello('world')
// ...
}
}
can be translated as:
const C = {
sayGoodBye : () => console.log('bye!'),
sayHello : who => console.log('Hello ' + who),
render : () => {
C.sayGoodBye()
C.sayHello('world')
}
}
if you try to define a variable inside a class using const/let/var it will result in an error.

Resources