ES6 method is not defined in create-react-app - javascript

I'm having difficulty understanding why create-react-app is unable to compile, telling me that error 'updateWord' is not defined no-undef. I'm fairly new to React with ES6. Normally I would write a component like const App = React.createClass({ }); but I've decided to try out some syntactical sugar instead.
I have parent component App and a child component Input:
class App extends Component {
constructor(props) {
super(props);
// all other code omitted...
}
handleInput(input) {
console.log(`handle: ${input}`);
updateWord(input);
// this also causes an error
// this.updateWord(input);
}
updateWord(input) {
console.log(`update ${input}`);
// why isn't this defined?
}
render() {
return (
<div className="App">
<Input onInput={this.handleInput} />
</div>
);
}
}
class Input extends Component {
handleInput(e) {
let input = e.target.value;
this.props.onInput(input);
}
render() {
return (
<form>
<input onChange={this.handleInput.bind(this)} />
</form>
);
}
}
I've tried changing to this.updateWord(input); instead of updateWord(input) but to no avail. I get:
"App.js:55 Uncaught TypeError: this.updateWord is not a function"
Normally when I implement a similar pattern (with ES5) to what I'm doing now I have no difficulties. For example:
const App = React.createClass({
getInitialState: function() {
// all other code omitted...
},
handleInput: function(input) {
console.log(`handle: ${input}`);
this.updateWord(input);
},
updateWord: function(input) {
console.log(`update ${input}`);
// In theory, this implementation would not cause any errors?
},
render: function() {
return (
<div className="App">
<Input onInput={this.handleInput} />
</div>
);
}
}

The problem is that when you do this.updateWord(...) in this.handleInput, this refers to the Input component. Let me illustrate the problem:
When you set the onInput handler, like so:
onInput={this.handleInput}
Here, since your Input component is calling the function, this refers to the Input component. This is due to the line:
this.props.onInput(input);
The Input component is calling handleInput. That means, in your handleInput function, the this context is Input. Consider the line:
this.updateWord(input);
in the handleInput function. Here you call this.updateWord, but since this is Input, it tries to call updateWord from Input which does not exist, thus throwing the error.
The solution is to explicitly bind the this context as the class (App component) instead of the Input component, using either Function.prototype.bind or an arrow function. From the documentation:
The bind() method creates a new function that, when called, has its this keyword set to the provided value
You can apply it like so:
onInput={this.handleInput.bind(this)}
Or more preferably in the constructor:
this.handleInput = this.handleInput.bind(this);
With the second option you may then do:
onInput={this.handleInput}
(This is more preferable as binding in the render method will create a new function every time on render, which isn't preferred).
The this context in the line above is the class. Since you bind this, the class will be correctly used as this context in the function and executing this.updateWord will invoke the method in the class.
An even more preferable way is to use arrow functions instead of regular ES6 methods. From the documentation:
An arrow function expression has a shorter syntax compared to function expressions and does not bind its own this, arguments, super, or new.target.
We can apply this by assigning handleInput to an arrow function instead of a regular method:
handleInput = (input) => {
console.log(`handle: ${input}`);
this.updateWord(input);
}
This will eliminate the use of bind completely and instead, use arrow functions. Since arrow functions don't bind their own this, it means this refers to the enclosing context. In the example above, a method is not used thus this refers to the class (the enclosing context). That will correctly call the class method updateWord, and consequently, you need not change the onInput event handler if you go this route.

Related

How to bind a function of a React component to "this" without a constructor?

As many know, this.someFunction = this.someFunction.bind(this) can be used in React class components. However, sometimes it's burdensome to create classes for very simple components. So, how can I bind a function to this without creating a class?
use arrow function arrow function
In React 16.8, you can use hooks for stateful components, essentially allowing you to write everything as a function and eliminating the need to use classes and all the caveats that come with them (this, .bind() etc).
Usage example
Here's an example of using the useState() hook and the useEffect() hook inside a function, along with an arrow function, which is already bound to the component's context:
import React, { useState, useEffect } from 'react';
function LimitedTextarea({ rows, cols, value, limit }) {
const [content, setContent] = useState(value);
const setFormattedContent = text => {
text.length > limit ? setContent(text.slice(0, limit)) : setContent(text);
};
useEffect(() => {
setFormattedContent(content);
}, []);
return (
<div>
<textarea
rows={rows}
cols={cols}
onChange={event => setFormattedContent(event.target.value)}
value={content}
/>
<p>
{content.length}/{limit}
</p>
</div>
);
}
Short explanation
You use useState() to create a state variable content and a method to update that variable, setContent().
You create an arrow function setFormattedContent to update the content state variable via the setContent method, which is already bound to context.
You use useEffect() to call setFormattedContent on the value of the content state variable.
Finally, you return whatever you would have in your render() method in a class component.
this makes sense in class component because it refers to component instance. It doesn't make sense in functional component because it is either undefined or a global, depending on the environment and how a function was declared.
As for class components, explicit constructor can be omitted if it's not needed, class fields can be used to assign instance properties, including bound methods:
class Foo extends Component {
foo = this.foo.bind(this);
foo() { ... }
...
}
Which is syntactic sugar for:
class Foo extends Component {
constructor(props) {
super(props);
this.foo = this.foo.bind(this);
}
foo() { ... }
...
}
Bound prototype methods have several benefits over instance arrow methods.
Yes arrow function is the solution.
Bind with this,
this.someFunction = this.someFunction.bind(this)
Using arrow function,
someFunction = () => {
// do something
}
There is no need to bind "this" If you use arrow function. It has simple and cleaner syntax.
someFuncton = () => {
// whatever write here...
}

React child calling parent handler function, does parent have to pass `this` to child? [duplicate]

class SomeClass extends Component{
someEventHandler(event){
}
render(){
return <input onChange={------here------}>
}
}
I see different versions of ------here------ part.
// 1
return <input onChange={this.someEventHandler.bind(this)}>
// 2
return <input onChange={(event) => { this.someEventHandler(event) }>
// 3
return <input onChange={this.someEventHandler}>
How are the versions different? Or is it just a matter of preference?
Thank you all for answers and comments. All are helpful, and I strongly recommend to read this link FIRST if you are confused as me about this.
http://blog.andrewray.me/react-es6-autobinding-and-createclass/
Binding is not something that is specifc to React, but rather how this works in Javascript. Every function / block has its own context, for functions its more specific to how its called. The React team made a decision for this to not be bound on custom methods on the class (aka not the builtin methods like componentDidMount), when adding ES6 support (class syntax).
When you should bind the context depends on the functions purpose, if you need to access props, state or other members on the class, then you would need to bind it.
For your example, each is different and it depends on how your component is set up.
Pre binding to your class
.bind(this) is used to bind the this context to your components function. However, it returns a new function reference each render cycle! If you don't want to bind on each usage of the function (like in a click handler) you can pre-bind the function.
a. in your constructor do the binding. aka
class SomeClass extends Component{
constructor(){
super();
this.someEventHandler = this.someEventHandler.bind(this);
}
someEventHandler(event){
}
....
}
b. make your custom functions on the class fat arrow functions. aka
class SomeClass extends Component{
someEventHandler = (event) => {
}
....
}
Runtime binding to your class
few common ways to do this
a. you can wrap your components handler function with an inline lambda (fat arrow) function.
onChange={ (event) => this.someEventHandler(event) }
this can provide additional functionality like if you need to pass additional data for the click handler <input onChange={(event) => { this.someEventHandler(event, 'username') }>. The same can be done with bind
b. you can use .bind(this) as described above.
onChange={ this.someEventHandler.bind(this) }
with additional params <input onChange={ this.someEventHandler.bind(this, 'username') }>
If you want to avoid creating a new function reference but still need to pass a parameter, its best to abstract that to a child component. You can read more about that here
In your examples
// 1
return <input onChange={this.someEventHandler.bind(this)}>
This is just doing a runtime event handler bind to your class.
// 2
return <input onChange={(event) => this.someEventHandler(event) }>
Another runtime bind to your class.
// 3
return <input onChange={this.someEventHandler}>
You are just passing the function as the callback function to trigger when the click event happens, with no additional parameters. Make sure to prebind it!
To summarize. Its good to think about how to optimize your code, each method has a utility / purpose depending on what you need.
Why bind a React function?
When you define a component using an ES6 class, a common pattern is for an event handler to be a method on the class. In JavaScript, class methods are not bound by default. If you forget to bind this.someEventHandler and pass it to onChange, this will be undefined when the function is actually called.
Generally, if you refer to a method without () after it, such as onChange={this.someEventHandler}, you should bind that method.
There three ways to bind your onChange function to the correct context
First
return <input onChange={this.someEventHandler.bind(this)}>
In this one we make use of bind explicitly to function to make the onChange event available as an argument to the eventHandler. We can also send some other parameter with type of syntax like
return <input onChange={this.someEventHandler.bind(this, state.value)}>
Second
return <input onChange={(event) => { this.someEventHandler(event) }>
This is a ES6 syntax, whereby we can specifythe parameters that we want to pass to the someEventHandler function. This is equivalent to .bind(this) however, It also gives us the flexibility to send other attributes along with the event like
return <input onChange={(event, value) => { this.someEventHandler(event, value) }>
Third
Define the function someEventHandler using Arrow function
someEventHandler = () => {
console.log(this); // now this refers to context of React component
}
An arrow function does not have its own this, the this value of the enclosing execution context is used and hence the above function gets the correct context.
or bind it in constructor like
constructor(props) {
super(props);
this.someEventHandler = this.someEventHandler.bind(this);
}
return <input onChange={this.someEventHandler}>
In this method, event is directly attached to the someEventHandler function. No other parameters can be passed this way

Why is 'this' itself undefined in function scope

I have the following code:
class App extends Component {
constructor(){
super()
//this.buttonOneClick = this.buttonOneClick.bind(this);
}
buttonOneClick() {
const { setTestData } = this.props;
setTestData("test");
}
render() {
const { testData } = this.props;
return (
<div className="App">
<h1>Test App</h1>
<div>{testData}</div>
<button onClick={this.buttonOneClick}>Test</button>
</div>
);
}
}
The component App is exported with react-redux's connect method to map the setTestData-function to the props (thats where setTestData is coming from).
When I set the buttonOneClick() handler without biding the component context to it (see the outcommented line in my code in constructor()) I get the following error:
Cannot read property 'props' of undefined
I understand that props wouldn't be defined since the handler is executed in the global context which doesn't know about props but how I understand the error it implies that this itself is not defined which doesn't make sense to me. Why is this the case? Shouldn't this always be defined in any execution context?
Thanks in advance
Shouldn't this always be defined in any execution context?
No.
There is no implicit this value in strict mode.
"use strict";
function example() {
alert(this);
}
example();
We’re getting an error because this is not defined when onClick calls our buttonOneClick() function.
Usually, you would fix this by binding this to the buttonOneClick function so it always stays the same. So we have to bind that in the constructor.
this.buttonOneClick = this.buttonOneClick.bind(this);
Possible work-around if you don't want to use the binding and all is to use the es2015 javascript arrow functions
buttonOneClick = () => console.log(this.props);
An arrow function does not have its own this so it will use this off its context, which is our Component. This is called Lexical Scoping

React: Can't call prop function when it is inside of another function?

I am trying to move over the Auth0 login function as described in their tutorial. I am able to get it work if I use it like this:
<button className="btn" onClick={this.props.route.auth.login.bind(this)}>test</button>
but if I set up the button to call a function I define above the render function like this:
login() {
this.props.route.auth.login.bind(this);
}
And change the onclick to be like this:
onClick={this.login()}
or
onClick={() => this.login()}
Then the auth login modal never opens and i receive no error. Also i added a console.log to login() and I can see it in the console, but the actual login modal never opens? It works in the first example, but not in the others.
The reason I am attempting to move this into a function is because I would like to pass the login function down into a child component later, and I was unable to do so and I believe this to be the root issue thats preventing me.
bind does not call your function:
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. docs
Also, you are setting the value of onClick prop to the return value of login. If you want to pass a reference to the function, you have to do it without the ().
Your code should look like this:
<button className="btn" onClick={() => this.login()}>test</button> <!-- You need to keep a reference to `this`, hence the binding -->
Then:
login() {
this.props.route.auth.login();
}
I edited the answer so that it uses an arrow function. However, I prefer not doing that, since it makes the code a bit cumbersome, and rather bind all the functions in the constructor, like #patrick-w-mcmahon did.
Let's say you have a container MyContainer and this container renders a view called MyView. This view has a button that calls a method. MyContainer is going to pass to the MyView the method it needs to use.
MyContainer:
class MyContainer extends React.Component {
constructor(props) {
super(props);
this.myFunc = this.myFunc.bind(this);
}
myFunc() {
console.log("hello world");
}
render() {
return <MyView myClick={this.myFunc}/>;
}
}
MyView:
const MyView = ({ myClick }) => {
return <button onClick={myClick} />;
};
MyView.propTypes = {
myClick: PropTypes.func
};
export default MyView;
You pass the needed function from the container to the view and the view calls its parents function from props. the use of bind() sets this scope to the current scope so that when you call this from a different scope it is going to be the scope of the bind. When you are in the render you run a different scope so you must bind your functions to the current class scope so that this.myReallyCoolFunction() is pointing to the correct scope (your class scope).
.bind() will only bind the object and arguments but won't call (run) the function.
TL;DR Just use .call() instead of .bind()
instead of .bind() you can use
.call(this, args) which is basicaly the same as bind only that call will call (run) the function.
you could also use .apply(), which is basicaly the same as .call() but takes an array with the arguments instead of object like .call()
this way you can avoid arrow functions in you jsx render()
and kind of keeping the line of thought with react.
something like ->
login() {
this.props.route.auth.login.call(this);
}
When you call props function through return(JSX) React takes care of calling it once propagation ends.

Why is it necessary to use bind when working with ES6 and ReactJS?

Using ES5 development with ReactJS, a component can be stated as the following:
var MyComponent = React.createClass({
alertSomething: function(event) {
alert(event.target);
},
render: function() {
return (
<button onClick={this.alertSomething}>Click Me!</button>
);
}
});
ReactDOM.render(<MyComponent />);
In this example, the this references the object itself, which is the expected natural behavior.
Question
My question is:
How you use ES6 to create components?
class MyComponent extends React.Component {
constructor(props) {
super(props);
}
alertSomething(event) {
alert(event.target);
}
render() {
return (
<button onClick={this.alertSomething.bind(this)}>Click Me!</button>
);
}
}
ReactDOM.render(<MyComponent />);
Knowing that in JavaScript the this references the instantiated object itself when using the new operator, someone can tell me what is the real purpose of using bind? It is something related to the internal mechanisms of React?
one of the purpose of bind in React ES6 classes is that you have to bind manually.
No Autobinding
Methods follow the same semantics as regular ES6 classes, meaning that >they don't automatically bind this to the instance. You'll have to >explicitly use .bind(this) or arrow functions =>:
We recommend that you bind your event handlers in the constructor so they >are only bound once for every instance:
constructor(props) {
super(props);
this.state = {count: props.initialCount};
this.tick = this.tick.bind(this); // manually binding in constructor
}
you can read more from the docs: https://facebook.github.io/react/docs/reusable-components.html
var cat = {
sound: 'Meow!',
speak: function () { console.log(this.sound); }
};
cat.speak(); // Output: "Meow!"
var dog = {
sound: 'Woof!'
};
dog.speak = cat.speak;
dog.speak(); // Output: "Woof!"
var speak = cat.speak;
speak(); // Output: "undefined"
speak = cat.speak.bind(dog);
speak(); // Output: "Woof!"
Explanation:
The value of "this" depends how the function is being called. When you provide this.alertSomething as your button's onClick handler, it changes how it will be called since you are providing a direct reference to that function, and it won't be called against your object instance (not sure if I'm phrasing that right).
The .bind function will return a new function where "this" is permanently set to the value passed to it.
ECMAScript 5 introduced Function.prototype.bind. Calling f.bind(someObject) creates a new function with the same body and scope as f, but where this occurs in the original function, in the new function it is permanently bound to the first argument of bind, regardless of how the function is being used.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
It's best to do this in your component's constructor so that .bind is happening just once for each of your handlers, rather than on every render.
bind is just core javascript. It's how binding events works. It's not a React concept.
The following article explains it pretty well.
Bounded function in JavaScript is a function that is bounded to a given context. That means no matter how you call it, the context of the call will stay the same.
To create a bounded function out of the regular function, the bind method is used. bind method take context to which you want to bind your function as a first argument. The rest of arguments are arguments that will be always passed to such function. It returns a bounded function as a result.
http://reactkungfu.com/2015/07/why-and-how-to-bind-methods-in-your-react-component-classes/
Also, on a side note, you should do all of your event binding in your constructor, not in your render method. This will prevent multiple bind calls.
Here's another good bit of information on the subject. They say:
We recommend that you bind your event handlers in the constructor so they are only bound once for every instance
https://facebook.github.io/react/docs/reusable-components.html

Categories