why would this.state not be available in this scenario? - reactjs

I have a component with the following functions:
constructor(MyProps: Readonly<MyProps>){
super(MyProps);
this.state = {suppliers: [], supplierId:0, supplierName:''};
this.addSupplier.bind(this);
}
addSupplier(){
const {supplierId} = this.state;
alert('supplierId = ' + supplierId);
}
<Button onClick={this.addSupplier}>Add</Button>
State is initialized as expected b/c this.state.supplierId is bound and displayed as expected in an html input in the component on load. The onChange handler within the html input also calls setState to update state.supplierId as expected. However, when the addSupplier() button gets triggered, the following error occurs:
TypeError: Cannot read property 'supplierId' of undefined
So for some reason, state is not available in this context. Any idea why this is?

Please use the arrow function to create the method
addSupplier = () => {}
or use the below syntax in the constructor
this.addSupplier = this.addSupplier.bind(this);

To expand on what Nikhil Goyal posted, the reason you're getting an error is because the context of this where the function is being invoked. Non-arrow functions implicitly bind their context when invoked rather then when they're declared. So, when you press the onClick on the Button component, it's searching for this.state.supplierId on the Button context.

Related

I am attempting to use setState in React

I'm attempting to use setState function to a method in my App class..
example of the current code:
addRandomContact() {
this.setState({
actors: contacts.slice(0, 6)
})
}
I am expecting my contacts array to change from a length of 5 to 6.
The error I am receiving is the following:
TypeError: Cannot read property 'setState' of undefined
addRandomContact
"this" keyword will not be accessible inside this function and hence its undefined.
You have to use arrow function like below:
addRandomContact = () => {
this.setState({
actors: contacts.slice(0, 6)
})
Though it's not very clear from your given codebase what is the issue but one possible error you could make is that you are not binding addRandomContact inside constructor of that class component. Try to paste the following code in your constructor and check if it solves
this.addRandomContact = this.addRandomContact.bind(this);

Why "this" keyword should be used in react click events?

I had a class component and then I created a button and added the onClick event to it.
Now I created a function to be called when that onClick event fires.
While referencing the function to onClick,
Why should we use something like {this.function-name} but not simply
{function-name}?
You may have many functions called function-name in different components. When you want to call them, you need to specify exactly which function you are referring to. Using the keyword this means you want to use the function-name which is attached to your current component.
this.function-name: function-name from the current component.
otherComponent.function-name: function-name from another component.
It is all about javascript scopes.
For example:
class Example extends Component {
clicked() {
console.log('clicked');
}
render() {
const innerFuncClicked = () => console.log('inner click');
return (
<button
onClick={clicked}
onClick={this.clicked}
onClick={this.clicked.bind(this)}
onClick={() => this.clicked()}
onClick={innerFuncClicked}
/>
);
}
}
As for the above code, I'll describe each "onClick" you will see.
Of course, you cant have several "onclick" as only the last one will override the rest.
1) function "clicked" is not defined in the scope so it will break
2) this will break as well as the "click" is happening inside the button component with a different "this"
3) this will work, as we bind the current "this" to the function
4) It will work as we create an arrow function that doesn't hurt the current "this"
5) this will work as the func "innerFuncClicked" exists in the scope
I would suggest you to read the basic understanding of 'this'.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
console.log(this === window); //true
Basically, this is keyword which help us to bind your custom function/ event to global 'window' events.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Not only for React, it's common for all JavaScript.

React event without binding this

I'm currently in the process of learning React and I've come across something that seems weird in React's Getting Started guides.
I'm currently reading this section.
There's this code sample: https://codepen.io/gaearon/pen/QKzAgB?editors=0011
It showcases conditional rendering, that's not the point of my question though.
When they pass the HandleLogout/LoginEvent, they just pass this.HandleLoginEvent, without binding or using arrow functions, yet this code works perfectly, how does it work?
The piece of code I'm talking about is this:
let button = null;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
In the previous section of the guides they explicitly state you have to use some method to bind the "this" in order for "this" not to be undefined when called from a child component, which makes sense.
Yet here "this" is somehow magically bound, how is it done?
Thanks, Avi.
EDIT: As Ori kindly pointed out, there's a bind call I've missed, problem solved :)
There are multiple ways to handle React binding pattern:
Bind in render
render() {
return (
<LogoutButton onClick={::this.handleLogoutClick} />
{/* or */}
<LogoutButton onClick={this.handleLogoutClick.bind(this)} />
)
}
Bind in constructor
As shown in the codepen, which explains why you don't see binding in render.
constructor(props) {
super(props)
this.handleLoginClick = this.handleLoginClick.bind(this)
// or
this.handleLoginClick = ::this.handleLoginClick
}
Use arrow function
When you use arrow function to declare handleLogoutClick, the function uses lexical binding.
Normally in JS, the value of this is determined by how a function is called. But with ES6 arrow function, we are able to create function that behaves differently -
it retains the this value of the enclosing lexical context, now we don't even have to call bind!
handleLogoutClick = () => {
this.setState({isLoggedIn: false});
}
// and you can simply
onClick={this.handleLogoutClick}
Personally I definitely prefer arrow function, as it produces cleaner code, and I don't have to write that constructor just to bind stuffs. I can simply do:
class LoginControl extends React.Component {
state = {isLoggedIn: false}
//... other stuffs ...
}
As for binding in render (or arrow function inside render), you should always avoid that.
When working with PureComponent, binding in render will cause unnecessary re-rendering.
Why Arrow Functions and bind in React’s Render are Problematic
constructor(props) {
super(props);
this.handleLoginClick = this.handleLoginClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
this.state = {isLoggedIn: false};
}
When you do it this way you avoid forgetting to bind them when passing them all over the place.

Can't access to response object with props

Im building an app with reactjs & redux and facing the following problem.
So basically I have a function like this :
onAdmissionFormSubmit(e){
e.preventDefault();
const { user } = this.props
console.log(user);
// If I do this const id = user.member.externalMemberId ....
// doesnt throw an error but if I log my const id it just says its undefined
}
It actually logs my object but if want to access the data inside of the object like user.member.externalMemberId it actually doesnt return an error but it will just says undefined.
What is it that im doing wrong?
console log of user: http://prntscr.com/fcxmou
According to your comments it seems that user is undefined, that leads me to believe that either you don't have a user object in this.props or you don't have a props object in this.
If it is the second choice, that can happen if you don't bind the handler method in to the class. In this situation, this refers to the element that triggered the handler and not to the class like you would expect.
You should do the binding in the constructor of the class:
constructor(props) {
super(props);
this.onAdmissionFormSubmit = this.onAdmissionFormSubmit.bind(this);
}

TypeError when using focus()

I have a react component having a input box. I used componentDidUpdate to set the focus to the input box. But my tests are failing with a typeError. Following is my code . Help me to pass the tests. Than you!!
This is my react component
`
public inputBox: any;
componentDidUpdate = () => {
this.inputBox.focus();
}
<div>
<input
ref = {element => this.inputBox = element}
/>
</div>
`
When the component is updated the tests are failed. giving me this error
TypeError: Cannot read property 'focus' of undefined
can any body can tell me whats wrong here?
Based on the official docs:
Note that when the referenced component is unmounted and whenever the
ref changes, the old ref will be called with null as an argument. This
prevents memory leaks in the case that the instance is stored, as in
the second example. Also note that when writing refs with inline
function expressions as in the examples here, React sees a different
function object each time so on every update, ref will be called with
null immediately before it's called with the component instance.
I believe that the ref callback gets passed null when the input is unmounted (that probably happens when your test ends and a different test starts). I think you just need to test for null when you want to focus the element, like in the docs:
<TextInput ref={function(input) {
if (input != null) {
input.focus();
}
}} />

Resources