Understanding the use of this inside a class method - javascript

I am having tough time understanding use of this keyword in Javascript.
The other questions on stackoverflow I stumbled upon have been more about calling a method or function using this keyword. Like using bind or ES6 arrow function and so on..
So I have this stateful component in React and we are using Axios to intercept request
import React, { Component } from 'react';
import Modal from '../../components/UI/Modal/Modal';
import Aux from '../Aux/Aux';
const withErrorHandler = ( WrappedComponent, axios ) => {
return class extends Component {
state = {
error: null
}
componentWillMount () {
this.reqInterceptor = axios.interceptors.request.use(req => {
this.setState({error: null});
return req;
});
this.resInterceptor = axios.interceptors.response.use(res => res, error => {
this.setState({error: error});
});
}
componentWillUnmount() {
axios.interceptors.request.eject(this.reqInterceptor);
axios.interceptors.response.eject(this.resInterceptor);
}
render () {
return (
<Aux>
<Modal
//Something
</Modal>
<WrappedComponent {...this.props} />
</Aux>
);
}
}
}
export default withErrorHandler;
Something like above code, Here in above code we call interceptors which we want to remove when we want componentWillMount (to avoid memory leaks)
For that the instructor did something like this in componentDidMount followed by
this.reqInterceptor = axios.interceptors.request.use(req => {
this.setState({error: null});
return req;
this in componentWillUnmount
axios.interceptors.request.eject(this.reqInterceptor);
[Question] Can some explain me this.reqInterceptor here? like shouldn't we create a constructor and declare it there and then use it (maybe I am thinking it wrong)?

To answer your question we need a good understanding of structure of React.Component first.
React stateful components are well design to leverage a bit of object-oriented programming (though you may achieve the same pattern in other paradigms.) You have this which refers to the whole component class at your disposal. You can retrieve or assign values to properties or call bounded methods to the component by referring to this within the scope.
In stateful components React executes componentDidMount() when the DOM is ready and mounted then according to your code you assign a value to reqInterceptor property of the component by this.reqInterceptor = value..., this is basically the component that we are returning from our function function withErrorHandler { return class extends Component {...} }.
This is a common pattern to dynamically create components on fly. We can apply same in the following example to demonstrate how this works in the scope of ES6 classes:
class Service {
constructor(x) {
this.x = x;
}
}
function getMyService(extra) {
return class extends Service {
getExtra() {
return extra; // extra value like WrappedComponent or axios
}
getX() {
return this.x;
}
};
}
// result
const MyService = getMyService('some extra value'); // Returns the class
const myServiceInstance = new MyService(1); // This is what React does to instantiate your component
console.log(myServiceInstance.getX()); // -> 1
console.log(myServiceInstance.getExtra()); // -> 'some extra value'
Update:
I updated the above example to be semantically close to React.Component

The constructor will be called with the new keyword, so since the method definition is not in the constructor, you could instantiate multiple objects and you won't register every time a listener.
In this case, he wants to tie the class method to the react lifecycle (componentWillMount and componentWillUnmount).

Related

Any way to make functions use variables from the place it was imported to? [duplicate]

I have multiple components which all need to do the same thing. (A simple function which maps over their child components and does something to each one). At the moment I am defining this method in each of the components. But I only want to define it once.
I could define it in the top level component and then pass it down as a prop. But that doesn't feel quite right. It is more a library function than a prop. (It seems to me).
What is the correct way of doing this?
Utils.js with latest Javascript ES6 syntax
Create the Utils.js file like this with multiple functions, etc
const someCommonValues = ['common', 'values'];
export const doSomethingWithInput = (theInput) => {
//Do something with the input
return theInput;
};
export const justAnAlert = () => {
alert('hello');
};
Then in your components that you want to use the util functions, import the specific functions that are needed. You don't have to import everything
import {doSomethingWithInput, justAnAlert} from './path/to/Utils.js'
And then use these functions within the component like this:
justAnAlert();
<p>{doSomethingWithInput('hello')}</p>
If you use something like browserify then you can have an external file i.e util.js that exports some utility functions.
var doSomething = function(num) {
return num + 1;
}
exports.doSomething = doSomething;
Then require it as needed
var doSomething = require('./util.js').doSomething;
If you want to manipulate state in helper functions follow this:
Create a Helpers.js file:
export function myFunc(){ return this.state.name; //define it according to your needs }
Import helper function in your component file:
import {myFunc} from 'path-to/Helpers.js'
In your constructor add that helper function to the class
constructor(){ super() this.myFunc = myFunc.bind(this) }
In your render function use it:
`render(){
{this.myFunc()}
}`
Here are some examples on how you can reuse a function (FetchUtil.handleError) in a React component (App).
Solution 1: Using CommonJS module syntax
module.exports = {
handleError: function(response) {
if (!response.ok) throw new Error(response.statusText);
return response;
},
};
Solution 2: Using "createClass" (React v16)
util/FetchUtil.js
const createReactClass = require('create-react-class');
const FetchUtil = createReactClass({
statics: {
handleError: function(response) {
if (!response.ok) throw new Error(response.statusText);
return response;
},
},
render() {
},
});
export default FetchUtil;
Note: If you are using React v15.4 (or below) you need to import createClass as follows:
import React from 'react';
const FetchUtil = React.createClass({});
Source: https://reactjs.org/blog/2017/04/07/react-v15.5.0.html#migrating-from-reactcreateclass
Component (which reuses FetchUtil)
components/App.jsx
import Categories from './Categories.jsx';
import FetchUtil from '../utils/FetchUtil';
import Grid from 'material-ui/Grid';
import React from 'react';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {categories: []};
}
componentWillMount() {
window
.fetch('/rest/service/v1/categories')
.then(FetchUtil.handleError)
.then(response => response.json())
.then(categories => this.setState({...this.state, categories}));
}
render() {
return (
<Grid container={true} spacing={16}>
<Grid item={true} xs={12}>
<Categories categories={this.state.categories} />
</Grid>
</Grid>
);
}
}
export default App;
I'll show two styles below, and you'll want to choose depending on how much the components' logic relate to each other.
Style 1 - Relatively related components can be created with callback references, like this, in ./components/App.js...
<SomeItem
ref={(instance) => {this.childA = instance}}
/>
<SomeOtherItem
ref={(instance) => {this.childB = instance}}
/>
And then you can use shared functions between them like this...
this.childA.investigateComponent(this.childB); // call childA function with childB as arg
this.childB.makeNotesOnComponent(this.childA); // call childB function with childA as arg
Style 2 - Util-type components can be created like this, in ./utils/time.js...
export const getTimeDifference = function (start, end) {
// return difference between start and end
}
And then they can be used like this, in ./components/App.js...
import React from 'react';
import {getTimeDifference} from './utils/time.js';
export default class App extends React.Component {
someFunction() {
console.log(getTimeDifference("19:00:00", "20:00:00"));
}
}
Which to use?
If the logic is relatively-related (they only get used together in the same app), then you should share states between components. But if your logic is distantly-related (i.e., math util, text-formatting util), then you should make and import util class functions.
Another solid option other than creating a util file would be to use a higher order component to create a withComponentMapper() wrapper. This component would take in a component as a parameter and return it back with the componentMapper() function passed down as a prop.
This is considered a good practice in React. You can find out how to do so in detail here.
Sounds like a utility function, in that case why not put it in a separate static utility module?
Otherwise if using a transpiler like Babel you can make use of es7's static methods:
class MyComponent extends React.Component {
static someMethod() { ...
Or else if you are using React.createClass you can use the statics object:
var MyComponent = React.createClass({
statics: {
customMethod: function(foo) {
return foo === 'bar';
}
}
However I don't advise those options, it doesn't make sense to include a component for a utility method.
Also you shouldn't be passing a method down through all your components as a prop it will tightly couple them and make refactoring more painful. I advise a plain old utility module.
The other option is to use a mixin to extend the class, but I don't recommend that as you can't do it in es6+ (and I don't see the benefit in this case).
Shouldn't you use a Mixin for this ? See https://facebook.github.io/react/docs/reusable-components.html
Although they are falling out of favour see https://medium.com/#dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750
Might be useful

React Context API, set context state from Child Components instead of passing functions as props

The React documentation says to pass the function defined in the Root component as a prop to the Child Component if you plan to update context from a nested component.
I have implemented the same:
import React from 'react';
const DataContext = React.createContext();
/**
* The App.
*/
export default class App extends React.Component {
constructor() {
super();
this.updateGreet = this.updateGreet.bind( this );
this.state = {
greet: '',
updateGreet: this.updateGreet
}
}
updateGreet() {
this.setState({
greet: 'Hello, User',
});
}
render() {
return (
<DataContext.Provider value={ this.state }>
<GreetButton />
<DisplayBox />
</DataContext.Provider>
)
}
}
/**
* Just a button element. On clicking it sets the state of `greet` variable.
*/
const GreetButton = () => {
return (
<DataContext.Consumer>
{
( { updateGreet } ) => {
return <button onClick={ updateGreet }>Greet</button>
}
}
</DataContext.Consumer>
)
}
/**
* Prints the value of `greet` variable between <h1> tags.
*/
const DisplayBox = () => {
return (
<DataContext.Consumer>
{
( { greet } ) => {
return <h1>{ greet }</h1>
}
}
</DataContext.Consumer>
)
}
It's a very simple React App I created for learning the Context API. What I'm trying to achieve is to define the updateGreet() method within the GreetButton component instead of defining it inside the App component since the function has nothing to do with the App component.
Another advantage I see is that if I choose to remove the GreetButton component altogether, then I need not keep track of all the methods it uses defined within another components.
Is there a way we can achieve this?
I would argue that the updateGreet method does have to do with App since it is manipulating App state.
I don't see this as a context-specific issue so much as the normal react practice of passing functions down to child components.
To accomplish your wish you could bind and pass the App's setState method to the provider and then implement updateGreet in the GreetButton component, but that would be an anti-pattern and I wouldn't recommend it.
When I am working with the Context API I typically define my context in a separate file and implement a custom provider to suit my needs, passing the related methods and properties down and consuming them throughout the tree as needed.
Essentially, implement what you have in App as its own Provider class GreetProvider. In the render method for GreetProvider simply pass the children through:
render() {
return (
<DataContext.Provider value={ this.state }>
{ this.props.children }
</DataContext.Provider>
)
}
Now, all of your greeting logic can live together at the source, with the context. Use your new GreetProvider class in App and any of its children will be able to consume its methods.

Why I'm able to use this.state without having to bind or use arrow function React

I know that arrow functions inherit the context of the parent, that's why they're so useful in React. However, I have this React component:
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import axios from 'axios';
class AlbumList extends Component {
constructor(props) {
super(props);
this.state = {
albums: [],
};
axios.get('https://rallycoding.herokuapp.com/api/music_albums')
.then(response => {
this.setState({ albums: response.data });
});
}
renderAlbums() {
const { albums } = this.state;
const array = albums.map(album => (
<Text>{album.title}</Text>
));
return array;
}
render() {
return (
<View>
{ this.renderAlbums() }
</View>
);
}
}
export default AlbumList;
And { this.renderAlbums() } is working complete fine without me having to transform renderAlbums() into an arrow function. I've been reading other answers on stackoverflow, but they all mention that you NEED arrow function or bind in order for this to work properly. But in my case it works fine as it is, so why use arrow function inside es6 class?
If you're using arrow functions then what "this" is is defined by the block that the function is defined in. If you're using "normal" functions then "this" is defined by the place the function gets called from. In this case you're calling it from within the render method so "this" is still an instance of the component. If you tried calling a function like that from something like a buttons onClick then it would fail to find "setState" as "this" would basically be defined by the actual rendered button and not the react class.
Simply the arrow functions inherit this from their parent's scope, but the regular functions inherit this from where the function gets called

State updates but does not render

I am new to ReactJS and am unsuccessfully attempting to manage a state change. The initial state renders as expected, the state successfully changes, however the elements do not render afterwards. There are no errors in the DOM console to go off of. I've made sure to set the initial state in the constructor of the component class, and I've also tried binding the method I'm using in the constructor since I've read auto-binding is not a part of ES6. The relevant component code is as follows:
class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
myIDs: Array(6).fill('0')
};
this.getMyIDs = this.getMyIDs.bind(this);
};
componentDidMount() {
var ids = this.getMyIDs();
ids.then((result)=> {
this.setState({ myIDs: result }, () => {
console.log(this.state.myIDs)
});
})
};
componentWillUnmount() {
this.setState({
myIDs: Array(6).fill('0')
});
};
getMyIDs() {
return fetch('/api/endpoint').then((response) =>{
return response.json();
}).then((myIDs) => {
return myIDs.result
})
};
render() {
return (
<Tweet tweetId={this.state.myIDs[0]} />
<Tweet tweetId={this.state.myIDs[1]} />
);
}
}
export default MyComponent
UPDATE: The 'element' being updated is the 'Tweet' component from react-twitter-widgets. Its source is here:
https://github.com/andrewsuzuki/react-twitter-widgets/blob/master/src/components/Tweet.js'
export default class Tweet extends React.Component {
static propTypes = {
tweetId: PropTypes.string.isRequired,
options: PropTypes.object,
onLoad: PropTypes.func,
};
static defaultProps = {
options: {},
onLoad: () => {},
};
shouldComponentUpdate(nextProps) {
const changed = (name) => !isEqual(this.props[name], nextProps[name])
return changed('tweetId') || changed('options')
}
ready = (tw, element, done) => {
const { tweetId, options, onLoad } = this.props
// Options must be cloned since Twitter Widgets modifies it directly
tw.widgets.createTweet(tweetId, element, cloneDeep(options))
.then(() => {
// Widget is loaded
done()
onLoad()
})
}
render() {
return React.createElement(AbstractWidget, { ready: this.ready })
}
}
As in React docs:
componentWillMount() is invoked just before mounting occurs. It is
called before render(), therefore calling setState() synchronously in
this method will not trigger an extra rendering. Generally, we
recommend using the constructor() instead.
Avoid introducing any side-effects or subscriptions in this method.
For those use cases, use componentDidMount() instead.
you should not use ajax calls in componentWillMount
call ajax inside: componentDidMount
another thing: why do you use
componentWillUnmount
the object will be removed no reason to have that call there.
The only issue that is present in your current code is that you are returning multiple Element component instances without wrapping them in an array of a React.Fragment or a wrapper div. With the latest version of react, you must write
render() {
return (
<React.Fragment>
<Element Id={this.state.myIDs[0]} />
<Element Id={this.state.myIDs[1]} />
</React.Fragment>
);
}
}
Also as a practice you must have your Async calls in componentDidMount instead of componentWillMount as the React docs also suggest. You might want to read this answer on where write async calls in React for more details
Another thing that you must remember while using prop Id in your Element component is that componentWillMount and componentDidMount lifecycle functions are only called on the initial Render and not after that, so if you are using this.props.Id in one of these function in Element component then you will not be able to see the update since the result of async request will only come later, check this answer on how to tacke this situation

Can we use bindActionCreators() on redux Action Creators defined in a class?

I have defined Redux action creators inside a class in the following manner:
export class ActionCreator {
login() {
return { type: 'LOGIN_STATUS' };
}
fbLoginStatusOK(user) {
return { type: 'LOGIN_OK', user };
}
}
Then inside a React components I am using them like this:
class Login extends React.Component {
login(e) {
e.preventDefault();
a = new ActionCreator(); // Simplified
dispatch(a.login());
};
render() {
return (
<div>
<h1>Login</h1>
<p>
<a href="#" onClick={this.login}>Login</a>
</p>
</div>
);
}
}
How can I use bindActionCreators on the 'ActionCreator' class or its object?
(So that every action creator is wrapped into a dispatch call so they may be invoked directly)
bindActionCreators uses Object.keys to iterate all function properties of an object and wrap them with a dispatch() call.
In your case, even if you use something like bindActionCreators(new ActionCreator()) it won't work, because Babel transpiles methods to non-enumerable properties.
A possible solution might be declaring all methods in the constructor:
class ActionCreator {
constructor() {
this.login = () => ({ type: 'LOGIN_STATUS' });
}
}
but that would miss the point.
Another possibility is to create your own utility, which would be similar to bindActionCreators but would use Object.getOwnPropertyNames instead of Object.keys. However, you should be cautious here and make sure you only wrap the methods you need (ignore constructor, for example).
I'm also wondering what's your motivation? isn't a bit of an overhead using a class instead of a plain object?

Categories