I'm trying to get my head around the scope of functions. _internalFunction works well, but how do I call _externalFunction instead?
I've tried self=this and then this._externalFunction inside _renderRow and also tried () => {this._externalFunction} but it didn't work.
class sandbox extends Component {
//some code removed for clarity
_renderRow(item) {
const _internalFunction = () => {
Alert.alert('Internal');
};
return (<Text onPress={_internalFunction}>{item}</Text>);
}
_externalFunction() {
Alert.alert('External');
};
}
Here's the code in React Native Playground to fiddle with:
https://rnplay.org/apps/5CIGvA
Thanks in advance! :)
In ES6 you need to manually bind this to the instance. Here is a quote from React documentation:
In React components declared as ES6 classes, methods follow the same
semantics as regular ES6 classes. This means that they don't
automatically bind this to the instance. You'll have to explicitly
use .bind(this) in the constructor:
Therefore you need to bind your function in constructor:
constructor() {
super();
this._externalFunction = this._externalFunction.bind(this);
}
And then you can use this._externalFunction in your component:
_renderRow(item) {
return (<Text onPress={this._externalFunction}>{item}</Text>);
}
Related
If I write a React class like this:
class SomeClass extends React.Component {
state = {
someState: this.someRegularFunction(),
someOtherState: this.someArrowFunction()
};
someRegularFunction() {
return "someText";
}
someArrowFunction = () => {
return "someOtherText";
};
}
Webstorm code assistance warns about the calling of arrow function this.someArrowFunction() saying:
Field 'someArrowFunction' is declared after 'state' and is possibly
not assigned yet
If does not warn about the call of the regular function this.someRegularFunction().
And Webstorm is correct, the execution fails when calling this.someArrowFunction() with:
TypeError: _this.someArrowFunction is not a function
I've been looking for some documentation explaining this behavior, but have been unable to find any.
Why can you call regular functions, but not arrow functions, before their declaration inside a class?
Because that code is functionally identical to this:
class SomeClass extends React.Component {
constructor(...args) {
super(...args);
this.state = {
someState: this.someRegularFunction(),
someOtherState: this.someArrowFunction()
};
this.someArrowFunction = () => {
return "someOtherText";
};
}
someRegularFunction() {
return "someText";
}
}
Field definitions are processed in source code order, when the instance is created. It's as though they were inserted into the constructor before any other code (in a base class) or just after the call to super (in a subclass).
In contrast, someRegularFunction is a method of the prototype, which is created when the class definition is evaluated, not later when the instance is created.
This is covered by the proposal for the class fields feature, in the specification text. (Reading spec text is not for the faint-hearted, though! :-) )
Side note: It's arguably a matter of style, but if you're doing that arrow function so that it can use this without your worrying about how it's called (for instance, as an event handler), you might consider making it a method and then using bind in the constructor (or effectively in the constructor) instead:
class SomeClass extends React.Component {
someFunction = this.someFunction.bind(this);
state = {
someState: this.someRegularFunction(),
someOtherState: this.someFunction()
};
someRegularFunction() {
return "someText";
}
someFunction() {
return "someOtherText";
}
}
That plays more nicely with testing code that may need to mock the function (by replacing it on the prototype).
But again, it's arguably a matter of style.
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...
}
In React's source code, the prototype function has a signature with three parameters:
function Component(props, context, updater) {
But everytime I see somebody extends React.Component using modern ES6 features, they declare constructor with only props as follows:
constructor(props)
What is the difference between a prototype function and constructor literal? And where do the rest two arguments go?
You can obviously use all of the three params provided in the Component. But in general, only in an advanced case we use props, not every time. Similarly, you can use others.
Here's an example with context api:
ES6 class component
class ContextConsumer extends React.Component {
/*
contexTypes is a required static property to declare
what you want from the context
*/
static contextTypes = {
currentUser: React.PropTypes.object
};
render() {
const {currentUser} = this.context;
return <div>{currentUser.name}</div>;
}
}
ES6 class component with an overwritten constructor
class ContextConsumer extends React.Component {
static contextTypes = {
currentUser: React.PropTypes.object
};
constructor(props, context) {
super(props, context);
...
}
render() {
const {currentUser} = this.context;
return <div>{currentUser.name}</div>;
}
}
Example taken from this blog. I will suggest you to look into the blog to be more familiar with it.
Another param is updater which you may have used this.forceUpdate() and doing so invoke the updater. But the fact, we do not use updater directly in normal case. Though, I have not faced such case to use the updater inside the constructor. You might be able to figure out if you face some advanced case.
To be more frank and to use react with clever, I never even try to use props as far as possible. They are just provided for us so that we can utilize in lifecycle hooks when needed.
Okay, let me explain it a little bit with react code:
function Component(props, context, updater) {
this.props = props;
this.context = context;
// If a component has string refs, we will assign a different object later.
this.refs = emptyObject;
// We initialize the default updater but the real one gets injected by the
// renderer.
this.updater = updater || ReactNoopUpdateQueue;
}
Component.prototype.forceUpdate = function(callback) {
this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
};
The Component function has 3 arguments which is being utilized inside the function. Later, its prototype forceUpdate is defined on which the updater is being hooked to enqueue the forceUpdate with enqueueForceUpdate. So, this.forceUpdate actually calling the Component updater and allows us to re-render the component. I hope, looking at its prototype method makes sense now.
What is the difference between a prototype function and constructor literal?
As far as I understand, you wanted to know why constructor is being called with the desired params.
The class/function constructor is used so that you can use an override to the function. For eg, passing props inside the constructor, you wanted to do an override with this. So, you explicitly notify the function to use the props as used inside the constructor.
So Es6 added the class keyword along with the constructor for it. It is however just syntactic sugar and is still based on the prototype model as before.
I don't know about the other two argos but I would guess it has to do with the function creating its own lexical scope.
I have a lot of methods in my top-level React component that I want to use as callbacks in its children components. I understand that in ES6 I must manually bind the context of each method. My current constructor method looks something like this:
this.method1 = this.method1.bind(this);
this.method2 = this.method2.bind(this);
this.method3 = this.method3.bind(this);
...
This works; all of my children are able to retain the intended context whenever they invoke their callbacks but it seems like a lot of code to write for something I did not even need to write in ES5. Is there a quick way to bind context to all of my component methods without having to write all of this boilerplate?
I understand that in ES6 I must manually bind the context of each method.
Yeah, except that's not entirely true. ES6 allows you to express things a lot better than you could in ES5.
Writing your code in ES6 doesn't mean you directly translate the code you have from ES5. There's more idiomatic ways to do it using new features in current versions of React and features that are native to ES6.
import {Component} from 'react'
class Foo extends Component {
// this class doesn't even need constructor
createButton(text) {
// don't write
// return <button onclick={this.handleClick.bind(this)}>{text}</button>
// instead write
return <button onclick={e=> this.handleClick(e)}>{text}</button>
}
handleClick(event) {
console.log(event, 'button was clicked')
}
render() {
var {buttons} = this.props;
// don't write
// return <div>{buttons.map(this.createButton.bind(this)}</div>
// instead write
return <div>{buttons.map(this.createButton, this)}</div>
}
}
export default Foo;
// <Foo buttons={["one", "two", "three"]} />
Notice I used context in two different ways that didn't require Function.prototype.bind
Arrow functions have a lexical this therefore a binding isn't required in most scenarios. Arrow functions are new to ES6.
Array.prototype functions like map,reduce,forEach accept a thisArgument which allows you to change the context of the callback. This is not new to ES6, so there's nothing stopping you from using this in your ES5 code today.
But do you also see this is a stateless functional component? Stateless functional components are available as of React 0.14
In idiomatic React code, most of the components you write will be stateless, simply composing other components. We’re introducing a new, simpler syntax for these components where you can take props as an argument and return the element you want to render
source: React Blog v0.14
This code is functionally identical to the component above but requires no class or context ceremony
const createButton = (text) => {
return <button onClick={handleClick}>{text}</button>
}
const handleClick = (event) => {
console.log(event, 'button was clicked')
}
// stateless functional component
const Foo = ({buttons}) => {
return <div>{buttons.map(createButton)}</div>
}
export default Foo;
Of course this approach cannot work for components that involve state (or life cycle methods), but it works for any Components that just use props - which is most of your components.
It's just one more technique you have to write React apps in an idiomatic way that doesn't involve Function.prototype.bind.
For what it's worth, I haven't relied upon Function.prototype.bind (with code I've written) in years.
If you are using Babel, you can enable stage 0 and use the :: this binding operator.
You should be able to bind to the parent context when passing to the children:
method1() {
...
}
render() {
return <ChildComponent method1={::this.method1} />;
}
https://babeljs.io/docs/plugins/preset-stage-0/
http://babeljs.io/docs/plugins/transform-function-bind/
There are various valid approaches here; the one I prefer is to use the #autobind decorator:
import autobind from 'autobind-decorator';
class MyComponent extends React.Component {
#autobind
method1() {
// "this" is bound correctly
}
}
This requires the autobind-decorator module (or core-decorators, which exposes a similar function), plus babel-preset-decorators-legacy.
I see a number of questions on here relating to this same issue, but it seems none match the issue I'm having, and are a bit more complex.
I am in the process of learning ReactJS and React Native. I'm in the midst of reading and following the code examples from "Learning React Native" book here: https://github.com/bonniee/learning-react-native
For some reason, calling this.setState in the code below when the handleTextChange function is called, causes the "this.SetState is not a function." error. My question is why? Unlike other questions about this same issue, I don't believe my call to this.stateState is buried in a callback function or if statement. Why is it undefined?
Here is my code:
class WeatherProject extends Component {
constructor(props) {
super(props);
this.state = {
zip: "",
forecast: null
};
}
_handleTextChange(event) {
this.setState({zip: event.nativeEvent.text});
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
You input {this.state.zip}.
</Text>
<TextInput
style={styles.input}
onSubmitEditing={this._handleTextChange}/>
</View>
);
}
}
Do not use bind inside a render. bind is a rather expensive operation and should only happen once. you have two options:
either bind the function in the constructor:
this._handleTextChange = this._handleTextChange.bind(this);
or use arrow function:
onSubmitEditing={(e) => this._handleTextChange(e)} />
Edit
Apparently arrow functions inside render is also a bad practice (Thx to Adam Terlson in the comments and answer below). You can read eslint docs which states:
A bind call or arrow function in a JSX prop will create a brand new function on every single render. This is bad for performance, as it will result in the garbage collector being invoked way more than is necessary.
Using arrow functions is obviously not as bad as using bind, but nevertheless should be avoided.
Regarding arrow function you also need to change _handleTextChange(event) function. Other answers didn't talk about how to change normal function to arrow function.
You need to change handler function, from:
_handleTextChange(event) {
this.setState({zip: event.nativeEvent.text});
}
To:
_handleTextChange = event => {
this.setState({zip: event.nativeEvent.text});
}
The issue is context binding, as identified in the other comments and answers here.
However, the performance of bind itself is a non-issue. The way-more-relevant issue is that using bind or arrows in your render methods creates a new function on each render, resulting in a change of props for the child that receives them, forcing a re-render.
You have two viable options:
class WeatherProject extends Component {
constructor(props) {
super(props);
this._handleTextChange = this._handleTextChange.bind(this);
}
// ...
}
Or you can use the class property notation and assign arrow functions if you're using the babel plugin for it.
class WeatherProject extends Component {
constructor(props) {
super(props);
// ...
}
handleTextChange = (event) => {
this.setState({zip: event.nativeEvent.text});
}
// ...
}
I strongly recommend you use the eslint package with the react recommended rules enabled. It will catch errors like using bind/arrows in your render, as well as tell you that underscore prefixed functions are ugly and totally not necessary in React. :)
this.setState is not a function--- Solved using this
let that = this;
that.setState({membersArray:response.data})
I had the same problem when trying to set the state. when I bind the function inside the constructor, the issue gets solved. check with below binding
constructor(props) {
super(props);
this.state = {
zip: "",
forecast: null
};
this._handleTextChange = this._handleTextChange.bind(this);
}