Variable undefined when used outside of component constructor - javascript

I'm working on a project with React and Electron and have an error. I have a component with a constructor that takes in props (which come in the form of two variables.) The constructor is instantiated in a separate file. The issue is that the variable works fine (for instance if do console.log to output it) in the constructor, but outside of it, the variables comes back undefined.
I've already tried using .bind to bind it, but that didn't help and it still turned up as undefined.
This is where the constructor is called:
const dropDown = new Dropdown({
editor,
monaco
});
Here is the constructor and an example of where I am trying to use the variables:
constructor(props) {
super(props);
// Define variables
this.editor = props.editor;
this.monaco = props.monaco;
// Returns correct object
console.log(this.monaco);
// Bind functions
this.changeLanguage = this.changeLanguage.bind(this);
this.filterFunction = this.filterFunction.bind(this);
this.dropDown = this.dropDown.bind(this);
}
changeLanguage(language) {
// Returns undefined all the time
console.log(this.monaco);
this.monaco.editor.setModelLanguage(this.editor, language);
}
I expect the variable to be the same in both the constructor and the functions elsewhere in the file, yet for some reason, it's only defined in the constructor.

You can use this.props.monaco. Or you can pass the props to the changeLanguage function if you rewrite it
changeLanguage(language, props) {
// Returns undefined all the time
console.log(props.monaco);
props.monaco.editor.setModelLanguage(this.editor, language);
}
and call it: this.changeLanguage('English', this.props)

Related

Why do we need to use bind() in ReactJS to access this.props or this.state? [duplicate]

This question already has answers here:
Why and when do we need to bind functions and eventHandlers in React?
(2 answers)
Closed 3 years ago.
look at this code for example
import React, { Component } from ‘react’;
class App extends Component {
constructor(props) {
super(props);
this.clickFunction = this.clickFunction.bind(this);
}
clickFunction() {
console.log(this.props.value);
}
render() {
return(
<div onClick={this.clickFunction}>Click Me!</div>
);
}
}
what's the purpose of bind(this) ? it binds the function clickFunction to the context of the object which clickFunction is already bound to , let me illustrate what i am trying to say with a normal javascript code :
class my_class {
constructor() {
this.run = this.run.bind(this)
}
run() {
console.log(this.data)
}
}
my_class.data = 'this is data'
new my_class().run() //outputs 'undefined'
and if you remove bind(this) it will give you the same results
constructor() {
this.run = this.run
}
results :
new my_class().run() //still outputs 'undefined'
i am sure i am understanding something wrong and this might the worst question on earth however i am new to es6 and i am not used to classes yet so i apologize for that
Blame JavaScript not React. This is done to retain object instance when the function is going to be passed. Certainly, it must be semantically correct for the function to expect such object. Most common case is to bind this when passing object method. The keyword This depends on how the function is called not how/where it is created. The relationship to This should be maintained at invocation.
Consider:
class Welcome extends React.Component {
render() {
return <button onClick={this.sayName}>Say My
Name</button>;
}
sayName() {
alert(this.props.name);
}
}
In React, you invoke like this: . This renders a button. Clicking the button should trigger an alert with "Bob".
Except it doesn't. Because in the above example, this would be undefined in the sayName function.
What's happening inside the render function is that this refers to the current instance of our React component. That component has a sayName function defined, so this.sayName points to our function, just fine and dandy.
But what React is doing behind the scenes is assigning this.sayName to another variable. That is, it's just like this:
let onClick = this.sayName;
onClick(); // Technically a click event is passed
to onClick
// but this doesn't matter for our purposes
We get an error. Because this is undefined. This is
extra confusing because in previous versions of React, React would "autobind" the event handler for you, so it would work. But at some point, Facebook decided to stop doing that, so ... here we are.
So how can we fix our component? We just do binding ourselves, like this:
<button onClick={this.sayName.bind(this)}>Say My
Name</button>;
Or with ES6 syntax:
<button onClick={() => this.sayName()}>Say My
Name</button>;
And it should work!

Why does it give an error 'searchInput' of undefined

I want to search for people. An array of data is stored in the redux store. I'm trying to perform a search, but an error occurs.
Cannot read property 'searchInput' of undefined
What could be the problem?
searchHandler(){
console.log('findUser', this.searchInput.value);
this.props.onFindPeople(this.searchInput.value)
}
I add an example code
You lost the context of this to the event handler.
You can either use an arrow function (that uses a lexical context for this):
searchHandler = () => {
console.log("findUser", this.searchInput.value);
this.props.onFindPeople(this.searchInput.value);
}
Or bind it to the class like this:
constructor(props){
super(props);
this.searchHandler = this.searchHandler.bind(this);
}
We do it in the constructor because it will run only once.
You are not binding the function. You need to bind it in constructor like below. Binding is required in order to access this and access state, props and modifying the state.
Please note you need to bind it only in constructor not anywhere else in the component
constructor(props){
super(props);
this.searchHandler = this.searchHandler.bind(this);
}
searchHandler(){
console.log('findUser', this.searchInput.value);
this.props.onFindPeople(this.searchInput.value);
}
Or you can also use arrow function as Sagiv mentioned in his answer.

Why exactly is bind(this) necessary in React constructors? [duplicate]

Something that is puzzling me is why when I define a react component class, values contained in the this object are undefined in methods defined (this is available in lifecycle methods) within the class unless I use .bind(this) or define the method using an arrow function for example in the following code this.state will be undefined in the renderElements function because I did not define it with an arrow function and did not use .bind(this)
class MyComponent extends React.Component {
constructor() {
super();
this.state = { elements: 5 }
}
renderElements() {
const output = [];
// In the following this.state.elements will be undefined
// because I have not used .bind(this) on this method in the constructor
// example: this.renderElements = this.renderElements.bind(this)
for(let i = 0; i < this.state.elements; i ++){
output.push(<div key={i} />);
}
return output;
}
// .this is defined inside of the lifecycle methods and
// therefore do not need call .bind(this) on the render method.
render() {
return (
<div onClick={this.renderElements}></div>
);
}
}
Then in the following example I do not need to use .bind(this) or an arrow function, this is available as expected in speak function
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
class Dog extends Animal {
speak() {
console.log(this.name + ' barks.');
}
}
var d = new Dog('Mitzie');
d.speak();
http://jsbin.com/cadoduxuye/edit?js,console
To clarify, my question is two part. One) why in the second code example do I not need to call .bind(this) to the speak function, but I do in the React component for the renderElements function and Two) why do the lifecycle methods (render, componentDidMount, etc) already have access to the class' this object, but renderElements does not.
In the React docs it says the following
[React Component Class] Methods follow the same semantics as regular ES6 classes, meaning that they don't automatically bind this to the instance.
But clearly they do, as the second code example I've posted shows.
Update
Both links in the first two comments show a working example of React classes NOT using .bind(this) on class methods and it works fine. But still in the docs is explicitly says you need to bind your methods, or use an arrow function. In a project using gulp and babel I can reproduce. Could it mean browsers have updated things?
Update 2
My initial code example had this.renderElements() called directly in the render function. That would work as expected without binding the function, or defining it with an arrow function. The issue occurs when I put the function as an onClick handler.
Update 3
The issue occurs when I put the function as an onClick handler.
In fact it is not an issue at all. The context of this changes when passed to the onClick handler, so that's just how JS works.
The value of this primarily depends on how the function is called. Given d.speak();, this will refer to d because the function is called as an "object method".
But in <div>{this.renderElements}</div> you are not calling the function. You are passing the function to React which will call it somehow. When it is called, React doesn't know which object the function "belonged" to so it cannot set the right value for this. Binding solves that
I actually think what you really want is
<div>{this.renderElements()}</div>
// call function ^^
i.e call the function as an object method. Then you don't have to bind it.
Have a look at MDN to learn more about this.
Event handlers in the component will not be bound automatically to the component instance like other methods ( life cycle methods...).
class MyComponent extends React.Component {
render(){
return (
<div onClick={this.renderElements}>
{this.renderElements()} <-- `this` is still in side the MyComponent context
</div>
)
}
}
//under the hood
var instance = new MyComponent();
var element = instance.render();
//click on div
element.onClick() <-- `this` inside renderElements refers to the window object now
Check this example to understand this more :
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
class Dog extends Animal {
run(){
console.log(this.name + ' runs');
}
speak() {
console.log(this.name + ' barks.');
this.run(); <-- `this` is still in the Dog context
return {onRun : this.run};
}
}
var d = new Dog('Mitzie');
var myDog = d.speak();
myDog.onRun() <-- `this` is now in the global context which is the `window` object
You can check this article for more information.
Functions in ES6 Classes - the case is explained very well by #Felix Kling. Every time you call a function on an object, this points to the object.
Lifecycle methods in React.Component - whenever React instantiates your component like myComponent = new MyComponent() it knows which object to call the lifecycle methods on, namely myComponent. So a simple call myComponent.componentDidUpdate() makes this available in the componentDidUpdate lifecycle method. Same for the other lifecycle methods.
Handlers & Bound in React.Component - this.state is undefined, because this is actually window - log it and see. The reason is that React invokes handlers on the global context, unless you have the handler bound to another context which overrides window (see #Phi Nguyen's answer also).
I think they have done that to allow you more flexibility, because in complex applications your handler may come from another component passed through props and then you would like to have the possibility to say: "Hey, React - this is not my component, but it's parent."
React's documentation is a bid misleading when it says
Methods follow the same semantics as regular ES6 classes, meaning that
they don't automatically bind this to the instance.
What they mean is that
var dog = new Dog('Mitzie');
speak = d.speak;
dog.speak() // this will be dog, because the function is called on dog
speak() // this will be window, and not dog, because the function is not bound
1.
Arrow Functions:
An arrow function expression has a shorter syntax compared to function expressions and lexically binds the this value (does not bind its own this, arguments, super, or new.target). Arrow functions are always anonymous. These function expressions are best suited for non-method functions and they can not be used as constructors.
Function.prototype.bind():
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
2.Component Specs and Lifecycle
To be absolutely clear: Most lifecycle methods are not bound, but called on an instance using the dot notation (true for componentWillMount, componentWillUnmount, componentWillReceiveProps and so on...), except componentDidMount which is bound to the instance since it gets enqueued into the transaction.
Just always put the autoBind(this); code in your constructor and never worry about method pointers.
npm install --save auto-bind-inheritance
const autoBind = require('auto-bind-inheritance');
class Animal {
constructor(name) {
autoBind(this);
this.name = name;
}
printName() { console.log(this.name); }
...
}
let m = new Animal('dog');
let mpntr = m.printName;
m.printName() //> 'dog'
mpntr() //> 'dog', because auto-bind, binds 'this' to the method.

Class properties for react lifecycle methods

Can I write React lifecycle methods as class properties?
I've been using class properties for a while as I like the fact that I no longer have to manually bind my methods, but I'd like to keep some consistency across my components and I'm wondering if there is any drawback on writing the React lifecycle methods as class properties
import React, { Component } from 'react';
class MyComponent extends Component {
render = () => {
return (
<div>Foo Bar</div>
);
}
}
export default MyComponent;
For example, is the context of this class property affected compared to the context in an equivalent method. Given that the render method in the above code is written as an arrow function, this concern seems relevant.
In a way, the true answer depends on your build pipeline and what the resulting Javascript output looks like. There are two primary possibilities:
Input Code
Let's start by saying you are writing the following before going through any sort of pipeline transformations (babel, typescript, etc):
class Test {
test = () => { console.log('test'); };
}
Output as class member variable.
In one possible world, your pipeline will also be outputting the test function as a member variable for the output class. In this case the output might look something like:
function Test() {
this.test = function() { console.log('test'); };
}
This means that whenever you write new Test() the test function is going to be recreated every single time.
Output as class prototype function
In the other major possibility, your pipeline could be recognizing this as a function property and escape it from the class instance to the prototype. In this case the output might look something like:
function Test() {
}
Test.prototype = {
test: function() { console.log('test'); }
}
This means that no matter how many times you call new Test() there will still be only one creation of the test function around in memory.
Desired behavior
Hopefully it's clear that you want your end result to have the function end up on the prototype object rather than being recreated on each class instance.
However, while you would want the function to not end up as a property, that doesn't necessarily mean you couldn't write it that way in your own code. As long as your build chain is making the correct transformations, you can write it any way you prefer.
Although, looking at the default babel settings (which your babeljs tag leads me to believe you are using) it does not make this transformation for you. You can see this in action here. On the left I've created one class with the function as a property and one class with the function as a class method. On the right hand side, where babel shows it's output, you can see that the class with the function as a property still has it being an instance-level property, meaning it will be recreated each time that class's constructor is called.
I did find this babel plugin, which seems like it might add this transformation in, but I've not used it for myself so I'm not positive.
In my experience, the most reason for writing a method as a class property is when the method will be passed as a callback, and you need it to always be bound to the instance. React lifecycle methods will always be called as a method, so there's no reason to bind them (and you incur a tiny memory penalty when you do). Where this makes a difference is when you're passing a function to a component as a callback (e.g. onClick or onChange).
Take this example:
class BrokenFoo extends React.Component {
handleClick() {
alert(this.props.message);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
)
}
}
The function represented by this.handleClick is not automatically bound to the component instance, so when the method tries to read the value of this.props it will throw a TypeError because this is not defined. Read this article if you're not familiar with this; the problem described in section 4.2 "Pitfall: extracting methods improperly" is essentially what's happening when you pass around a method without making sure it's bound correctly.
Here's the class, rewritten with the handler as a class property:
class HappyFoo extends React.Component {
handleClick = () => {
alert(this.props.message);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
)
}
}
Effectively, you can think of the handleClick definition in the second example as placing this code into the component's constructor (which is just about exactly the way Babel does it):
this.handleClick = () => {
alert(this.props.message);
}
This achieves the same thing as calling bind on the function (as described in the linked article) but does it a little differently. Because this function is defined in the constructor, the value of this in this.props.message is bound to the containing instance. What this means is that the function is now independent of the calling context; you can pass it around and it won't break.
The rule of thumb that I follow: by default, write methods as methods. This attaches the method to the prototype and will usually behave the way you'd expect. However, if the method is ever written without parentheses (i.e. you're passing the value and not calling it), then you likely want to make it a class property.

When can we avoid using a constructor to initialize state?

In the example given on the reactnativeexpress website here, state = {count: 0} is used in place of a constructor to initialize the count variable.
In the official Facebook docs here, they've said
In general, you should initialize state in the constructor, and then call setState when you want to change it.
So I created a constructor to initialize count in the same manner:
constructor(props) {
super(props);
this.state = {count: 0}
}
The code seems to work the same way (at least on the surface), so what's the difference between creating a constructor and initializing count as in the example?
In the example that you attach as a link they use the ES Class Fields which is a proposal (currently in stage 2).
That means you will need some extra presets / plugins of babel (or any other JavaScript compiler) to support it as it's not part of the official specifications of ECMAScript yet.
In the other example, you use the class constructor which is part of ES2015.
Both will get you the same results, a property attached to the instance of the class.
which is basically just a syntactic sugar for the prototype pattern.
This has more to do with ES6 Classes.
getFullName() {
return this.props.firstName + this.props.lastName;
}
The above function will throw an error saying props is not defined.
getFullName = () => {
return this.props.firstName + this.props.lastName;
}
The above code will pass the context of this into the function and will work good.
Similarly, your
state = {count: 0}
is executed in the context of the class [using appropriate this ].
The same state needs to be called using this.state within the constructor to bind it to appropriate context.

Categories

Resources