When I'm overriding a function in a child class, how can I call the parent version of that function?
Say I have two components AbstractList and SortableList in React with:
class AbstractList extends React.Component {
getItems() {
...
}
}
class SortableList extends AbstractList {
getItems() {
... do sorting first
return super.getItems(); // QUESTION: how am I supported to actually do this?
}
}
Thanks!
You should not do it this way
check this issue on github
Many people have become accustomed to using OO inheritance not just as
a tool, but as the primary means of abstraction in their application.
I've you've worked at a Java shop, you'll know what I'm talking about.
In my personal opinion, classical OO inheritance (as implemented in
many popular languages) is not often the best tool for most jobs, let
alone all jobs. But the situation should be approached with even more
caution when inheritance is used within a framework or paradigm that
uses functional composition as its primary abstraction (React). There
are certain patterns we'll want to prevent (there are many strange
things that people can come up with when combining render with
inheritance that don't make sense and are addressed via simple
composition). There's also risk of making mutation more convenient. It
might make sense to start with ES6 classes simply as a better syntax
for React component creation, intentionally limiting some use cases
(limiting inheritance depth, making some React base class methods
final) (only when used with React components of course - all non-React
use of ES6 classes wouldn't be restricted).
Instead of this
class AbstractList extends React.Component {
getItems() {
...
}
}
class SortableList extends AbstractList {
getItems() {
... do sorting first
return super.getItems();
}
}
You should do
class AbstractList extends React.Component {
getItems() {
...
}
}
class SortableList extends React.Component {
render() {
return <AbstractList items={this.props.item}>{this.props.children}</AbstractList>;
}
}
Related
I always use this expression in my components:
class Cart extends Component { }
Recently I have seen a lot of codes using this expression.
class Cart extends React.Component {
constructor(props) {
super(props);
}
}
Why is it? What is the purpose of using constructor and super?
Is React.Component and Component same?
Why do we pass props in constructor and super?
I am not asking what super and constructor are, I am asking difference between 2 codes above and benefits of using each one?
I checked online but did not see any explanation, just code examples.
Constructors and super are not react specific or even javascript specific. They are specific to the inheritance in OOP.
Constructors
Constructors are what can be called as initializing functions in a class. Let's look at an example where a constructor can be used.
class parentClass {
constructor(){
this.foo = foo;
this.bar = bar;
}
function sharedMethod1(){
print(this.foo);
}
function sharedMethod(){
print(this.bar)
}
}
object1 = new ParentClass(foo1, bar1);
object1.sharedMethod1() // this will print foo1;
object1.sharedMethod2() // this will print bar1;
object2 = new ParentClass(foo2, bar2);
object2.sharedMethod1() // this will print foo2;
object2.sharedMethod2() // this will print bar2;
when there is a need to create multiple instances of a class with different values for member variables / functions, we make use of the constructor functions.
Super
The super keyword is used in inheritance as well. In inheritance when extending a child class from a parent class, there is a need to initialise the constructor of the parent class. The super keyword is used for this purpose. let's look at the below example for super.
class ParentClass (){
constructor(){
this.foo = foo;
}
}
class childClass extends ParentClass(){
super(foo1); // super is used here initialize the constructor of the ParentClass
}
The same principle mentioned above is followed in React as well.
Please look into dan abramov's blog post on constructor and super here https://overreacted.io/why-do-we-write-super-props/
Dan Abramov mentions on his blog that:
You can’t use this in a constructor until after you’ve
called the parent constructor.
JavaScript won’t let you.
JavaScript enforces that if you want to use this in a constructor, you
have to call super first.
calling super(props) is needed in order to access this.props.
as mentioned on this thread, there are 2 main reasons to use a constructor on a react component:
Initializing local state by assigning an object to this.state.
Binding
event handler methods to an instance.
If you don’t initialize state and you don’t bind methods, you don’t need to implement a constructor for your React component.
If you don’t initialize state and you don’t bind methods, you don’t
need to implement a constructor for your React component.
Copied from reactJS website.
If you don’t initialize state and you don’t bind methods, you don’t
need to implement a constructor for your React component.
The constructor for a React component is called before it is mounted.
When implementing the constructor for a React.Component subclass, you
should call super(props) before any other statement. Otherwise,
this.props will be undefined in the constructor, which can lead to
bugs.
Typically, in React constructors are only used for two purposes:
Initializing local state by assigning an object to this.state.
Binding event handler methods to an instance.
You should not call setState() in the constructor(). Instead, if your
component needs to use local state, assign the initial state to
this.state directly in the constructor:
Constructor is the only place where you should assign this.state
directly. In all other methods, you need to use this.setState()
instead.
Avoid introducing any side-effects or subscriptions in the
constructor. For those use cases, use componentDidMount() instead.
https://reactjs.org/docs/react-component.html
And here is the purpose of super() ,
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super
I tried with babel, Here's what I get.
With Constructor I get this function,
class App extends React.Component{
constructor(props){
this.state = {}
}
}
Related part in ES5,
var App =
/*#__PURE__*/
function (_React$Component) {
_inherits(App, _React$Component);
function App(props) {
var _this;
_classCallCheck(this, App);
_this.state = {};
return _possibleConstructorReturn(_this);
}
return App;
}(React.Component);
Without Constructor
class App extends React.Component{
state = {}
}
ES5 code
var App =
/*#__PURE__*/
function (_React$Component) {
_inherits(App, _React$Component);
function App() {
var _getPrototypeOf2;
var _temp, _this;
_classCallCheck(this, App);
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _possibleConstructorReturn(_this, (_temp = _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(App)).call.apply(_getPrototypeOf2, [this].concat(args))), _this.state = {}, _temp));
}
return App;
}(React.Component);
Why is it? What is the purpose of using constructor and super?
Constructors and the super-keyword are not react specific, but JavaScript specific. Search for inheritance and "OOP" in JavaScript to better understand it (e.g. this medium article). super and inheritance is also not only bound to JavaScript, many other languages also use it and explain it accordingly, here for example is a good explanation of how the super-keyword should be used in java.
Why do we pass props in constructor and super?
Check Why Do We Write super(props)?.
Is React.Component and Component same?
Yes. In the head-section of the files are a bunch of import ...-statements. For React.Component you will find something like import * as React from "react" or import React from "react". In case of Component you will find import { Component } from "react". Check the import-documentation from MDN for more information.
I am asking difference between 2 codes above and benefits of using each one?
There is no difference in the result. Both versions work the same and there is no (notable) difference in performance. One version is shorter and less noisy. If you have no further instructions in the constructor, I would recommend suppressing it.
As per recommendations from others, I have been binding class methods in the constructor in React, for example:
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
I have components with many methods, and I am binding all of these methods to this. Argh, what a pain! To avoid repetitively maintaining this pattern, I built a function that would be called in the constructor in place of all the individual calls; it binds all the methods specific to that class, while a parent class would take care of its own methods moving up the classes. For example:
function bindClassMethodsToThis(classPrototype, obj) {
Object.getOwnPropertyNames(classPrototype).forEach(prop => {
if (obj[prop] instanceof Function && prop !== 'constructor') {
obj[prop] = obj[prop].bind(obj);
console.log(`${classPrototype.constructor.name} class binding ${prop} to object`);
}
});
}
class A {
constructor() {
bindClassMethodsToThis(A.prototype, this);
}
cat() {
console.log('cat method');
}
}
class B extends A {
constructor() {
super();
bindClassMethodsToThis(B.prototype, this);
}
dog() {
console.log('dog method');
}
}
let b = new B();
So, React and ES6 gurus, is this a reasonable approach, or I am doing something wrong here? Should I stick to the individual bindings to this?
Your strategy seems sound, though there are some edge cases that you may end up wanting to tackle. A library like react-autobind, which Alexander mentioned, takes care of some of these things for you, and if I were to use this strategy I would probably use a library like this one (or take a look into the source code to get an idea for what it does).
For completeness, some alternative approaches are:
Use class properties and arrow functions (along with any necessary Babel transforms) to create pre-bound methods:
class MyComponent extends React.Component {
handleChange = () => { /* ... */ }
}
Use a decorator, like the autobind decorator from core-decorators, along with any necessary Babel transforms (this was the strategy I used previously):
import { autobind } from 'core-decorators'
class MyComponent extends React.Component {
#autobind
handleChange() { /* ... */ }
}
Explore the use of Hooks (currently in alpha) to avoid the problem of binding all together (since state values and setters exists as local variables to be closed over). This is the strategy I've been preferring very recently, but please note it is still in the proposal state and may change. :)
Assuming you have Babel setup for it, you can also use arrow functions instead, avoiding the need to bind this:
class Foo extends React.Component {
handleClick = (event) => {
event.preventDefault()
}
render() {
return <div onClick={this.handleClick}>Click me</div>
}
}
One way to resolve this is to call bind in render:
onChange={this.handleChange.bind(this)}
I have a legacy Backbone app which I have begun to rewrite in React. The app has a main view containing two subviews, arranged vetically. The top panel displays some data, and the bottom one displays the result of some algorithm taking this data as input. Since I have many different data sources, each with a different algorithm applied to it, I have an abstract base View class, which I then subclass for each data source, adding, decorating and overriding methods as necessary. Somewhat like this:
// Base View.
const BaseView = Backbone.View.extend({
events: {},
initialize() {
this.subViewA = // instantiate subview...
this.subViewB = // instantiate subview...
},
generateResultData() {
// 'Abstract' method which should be specialised to generate data rendered by subViewB...
},
render() {
// render subviews...
},
});
// Derived View.
const Derived = BaseView.extend({
events: {
// event handlers...
},
add(a, b) {
return a+b;
},
// additional methods...
generateResultData() {
return {
result: this.add(2,2);
}
},
})
This results in a shallow hierarchy of many similar View classes. It's all terribly imperative, but it's a simple, intuitive and easy-to-reason-about pattern, and just works. I'm struggling to see how to achieve the same thing in React, however. Given that subclassing of subclasses of React.Component is considered an anti-pattern, my focus has naturally been on composition, and in particular Higher Order Components. HOCs (which I find beautiful, but unintuitive and often just downright confusing) seem to involve adding general features, rather than specialising/refining something more general. I have also considered passing in more specialised versions of Componenet methods through props. but that just means I have to use the same boilerplate Component definition over and over again:
// General functional component, renders the result of prop function 'foo'.
function GeneralComponent(props) {
const foo = this.props.foo || ()=>"foo";
return (
<div>
<span> { this.props.foo() } </span>
</div>
)
}
// Specialised component 1, overrides 'foo'.
class MySpecialisedComponent extends React.Component {
foo() {
return this.bar()
}
bar() {
return "bar"
}
render() {
return (
<GeneralComponent foo={this.foo} />
)
}
}
// Specialised component 2, overrides 'foo' and adds another method.
class MyOtherSpecialisedComponent extends React.Component {
foo() {
return this.bar() + this.bar()
}
bar() {
return "bar"
}
baz() {
return "baz"
}
render() {
return (
<GeneralComponent foo={this.foo} />
)
}
}
The above is a very simplistic case, obviously, but essentially captures what I need to do (though I would of course be manipulating state, which the example does not do, for simplicity). I mean, I could just do things like that. But I want to avoid having to repeat that boilerplate all over the place. So is there a simpler and more elegant way of doing this?
Generally, if a component is stateless and doesn't use lifecycle hooks, there are no reasons for it to be Component class. A class that acts as a namespace and doesn't hold state can be considered an antipattern in JavaScript.
In constrast to some other frameworks, React doesn't have templates that would need to map variables in order for them to be available in view, so the only place where bar function needs to be mentioned is the place where it's called. JSX is an extension over JavaScript, JSX expressions can use any names that are available in current scope. This allows to compose functions without any classes:
const getBar => "bar";
const getBaz => "baz";
const getBarBaz => getBar() + getBaz();
const MySpecialisedComponent = props => <GeneralComponent foo={getBar} />;
const MyOtherSpecialisedComponent = props => <GeneralComponent foo={getBarBaz} />;
An anonymous function could be passed as foo prop instead of creating getBarBaz but this is generally discouraged because of unnecessary overhead.
Also, default prop values could be assigned with defaultProps without creating new ()=>"foo" function on each component call:
function GeneralComponent({ foo }) {
return (
<div>
<span> {foo()} </span>
</div>
)
}
GeneralComponent.defaultProps = { foo: () => 'foo' };
IMO what is throwing you off isn't inheritance vs composition, it's your data flow:
For example, many of my derived views need to do custom rendering after the main render. I'm using a third-party SVG library, and the data rendered into the 'result' subview is derived from analysis of rendered SVG elements in the main data view above it
So what you're trying to do here is have a child update props of a distantly related component after render, correct? Like this?
// after the svg renders, parse it to get data
<div id="svg-container">
<svg data="foo" />
<svg data="bar />
</div>
// show parsed data from svg after you put it through your algos
<div id="result-container">
// data...
</div>
There's a lot of state management libraries out there that will help you with this problem, that is, generating data in one component and broadcasting it to a distantly related component. If you want to use a tool built-in to react to address this you may want to use context, which gives you a global store that you can provide to any component that wants to consume it.
In your example your child classes have data-specific methods (add, etc.). IMO it's more typical in react to have a generic class for displaying data and simply passing it down map functions as props in order to rearrange/transform the rendered data.
class AbstractDataMap extends PureComponent {
static defaultProps = {
data: [],
map: (obj, i) => (<div key={i}>{obj}</div>)
};
render() {
const { data, map, children } = this.props;
const mapped = data.map(map);
return (
<Fragment>
{mapped.map((obj, i) => (
children(obj, i)
))}
</Fragment>
);
}
}
// in some other container
class View extends Component {
render() {
return (
<div>
<AbstractDataMap data={[1, 2, 3]} map={(n) => ({ a: n, b: n + 1 })}>
{({ a, b }, i) => (<div key={i}>a: {a}, b: {b}</div>)}
</AbstractDataMap>
<AbstractDataMap data={[2, 4, 6]} map={(n) => (Math.pow(n, 2))}>
{(squared, i) => (<div key={i}>squared: {squared}</div>)}
</AbstractDataMap>
</div>
);
}
}
IMO this pattern of using an HOC to abstract away the labor of explicitly using .map in your render calls (among other uses) is the pattern you are looking for. However, as I stated above, the HOC pattern has nothing to do your main issue of shared data store across sibling components.
Answering my own question, which I've never donw before...
So my question really arose from a concern that I would need to refactor a large, imperative and stateful codebase so as to integrate with React’s composition-based model (also with Redux). But it occurred to me after reading the (very insightful and helpful) responses to my question that my app has two parallel parts: the UI, and an engine which runs the algorithms (actually it's a music analysis engine). And I can strip out the Backbone View layer to which the engine is connected quite easily. So, using React’s context API I've built an ‘AnalysisEngineProvider', which makes the engine available to subcomponents. The engine is all very imperative and classically object-oriented, and still uses Backbone models, but that makes no difference to the UI as the latter has no knowledge of its internals - which is how it should be (the models will likely be refactored out at some point too)...
The engine also has responsibility for rendering the SVG (not with BB views). But React doesn’t know anything about that. It just sees an empty div. I take a ref from the div and pass it to the engine so the latter knows where to render. Beyond that the engine and the UI have little contact - the divs are never updated from React state changes at all (other components of the UI are though, obviously). The models in the engine only ever trigger updates to the SVG, which React knows nothing about.
I am satisfied with this approach, at least for now - even if it's only part of an incremental refactor towards a fully React solution. It feels like the right design for the app whatever framework I happened to be using.
The following Typescript code using React compiles and works just fine:
import * as React from "react";
class MyComponent<P> extends React.Component<P, any> {
static getFactory() {
return React.createFactory(this);
}
}
However, the following code, similar in every way except the class is now abstract, throws an error at compilation, on the line where the factory is created:
import * as React from "react";
abstract class MyComponent<P> extends React.Component<P, any> {
static getFactory() {
return React.createFactory(this);
}
}
The error is:
error TS2345: Build:Argument of type 'typeof MyComponent' is not assignable to parameter of type 'ComponentClass<any> | StatelessComponent<any>'.
I can think of no reason why it should make a difference whether the class is marked as abstract or not.
Any insights as to why this might be the case?
================ADDED 9/22/2016=============
In my example above, I probably should have called MyComponent something like MyBaseComponent. The whole point here is that I am creating a framework component that I never want instantiated. I only want things derived from MyComponent to ever be instantiated. (Note, for example, that MyComponent doesn't even have a render() method declared.)
So.... I declare a really-to-be-instantiated class as:
interface MyDerivedComponentProps {
id: string;
}
class MyDerivedComponent extends MyComponent<MyDerivedComponentProps> {
render() {
return /* Some JSX rendering stuff here */
}
}
Note that this all works just fine.... if I don't ever instantiate MyComponent but do instantiate MyDerivedComponent. But the simple act of decorating MyComponent with the abstract keyword, which ought to serve to ensure that MyComponent will never be directly instantiated causes this compiler error. And I'm still of the opinion that it shouldn't. The compiler is handling the inheritance just fine if the base class is not marked as abstract. It should also handle it fine if the base class is marked as abstract, or perhaps not, but if not, why?
================ADDED 9/29/2016=============
As per request in comments, here is a complete example code showing both declarations and inheritance for both:
import * as React from "react";
import * as ReactDOM from "react-dom";
interface MyDerivedComponentProps {
id: string;
}
// WORKING EXAMPLE
class MyBaseNonAbstractComponent<P> extends React.Component<P, any> {
static getFactory() {
return React.createFactory(this); // NO COMPILER ERROR HERE
}
}
class MyDerivedFromNonAbstractComponent extends MyBaseNonAbstractComponent<MyDerivedComponentProps> {
render() {
return <div>Hello from id {this.props.id}</div>;
}
}
// NOT WORKING EXAMPLE
abstract class MyBaseAbstractComponent<P> extends React.Component<P, any> {
static getFactory() {
return React.createFactory(this); // HERE IS THE COMPILER ERROR
}
}
class MyDerivedFromAbstractComponent extends MyBaseAbstractComponent<MyDerivedComponentProps> {
render() {
return <div>Hello from id {this.props.id}</div>;
}
}
ReactDOM.render(MyDerivedFromNonAbstractComponent.getFactory()({ id: "idForNonAbstract" }), document.getElementById("managed-content-for-non-abstract"));
ReactDOM.render(MyDerivedFromAbstractComponent.getFactory()({ id: "idForAbstract" }), document.getElementById("managed-content-for-abstract"));
================ADDED 9/29/2016 #2=============
It is definitely the case that whether or not a base class is marked abstract, if it has a static method on it, and that method refers to this, then it will actually dereference to the constructor of the derived class used to invoke the method.
So, if we have the following:
class BaseConcrete {
static logWhoAmI() {
console.log(`this is ${this}`);
}
}
class DerivedConcrete extends BaseConcrete {
}
DerivedConcrete.logWhoAmI(); // This will log constructor of DerivedConcrete
abstract class BaseAbstract {
static logWhoAmI() {
console.log(`this is ${this}`);
}
}
class DerivedAbstract extends BaseAbstract {
}
DerivedAbstract.logWhoAmI(); // This will log constructor of DerivedAbstract
So it appears that Typescript does not treat this referred to in a static method of a base class any differently when that base class is abstract or not.
It is only, somehow, the signature of the React.createFactory() method that seems to get confused somehow when passed the "this". It complains because on the face of it, it seems as if it is being passed a constructor for an abstract method, which would of course be illegal. But since the class itself is abstract, the this at runtime is guaranteed to be a derived class, and React.createFactory should work just fine. In fact, as one commenter pointed out, if you cast the argument to React.createFactory to any, it will work fine at runtime. But this is hack it seems to me. Appreciate the discussion this far though.
Abstract classes cannot be directly instantiated with new (that's why they are called so). Thus, you can't use them as React components. They can be the base classes for other components, though.
And that's the thing TypeScript compilers checks statically. Since abstract class doesn't have new operator, it cannot be coerced to ComponentClass.
We're currently building a React-Redux frontend with a REST API backend powered by Node. I'm unsure about whether to use a Redux or a simple call to the API on mounting the component.
The component is a simple list of profiles which are going to be displayed throughout (but not constantly) the site.
Sorry for asking this. Maybe there's something to read through available?
I would advice you to take a look at two things:
1) The first React tutorial on Facebook is very underrated:
https://facebook.github.io/react/docs/thinking-in-react.html
It exposes a very clear way to think about how to think about the tree structure of your views.
2) From there, move to reading about Containers and Components:
https://medium.com/#dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0
This post explains that React components too often do two things: act as renderers and as controllers (taking on both the V and the C on MVC).
Now, what your React view needs is a controller. Fetching it whenever you mount the component overlaps two different concerns: how to display the information and how to fetch it.
You could do it with a single, bigger React component that manages the complete state of your application:
class MyApp extends React.Component {
componentDidMount() {
fetch('/profiles').then(res => res.json().then(::this.setState))
}
render() {
if (this.state) {
return <ProfileList profiles={this.state} />
} else {
return <span>Loading...</span>
}
}
}
That would be your "Container". Your "Component" is a pure representation of the list of profiles, that needs not care about how that information was retrieved:
class ProfileList extends React.Component {
render() {
return <ul>
{
this.props.profiles.map(
profile => <li key={profile.id}>{profile.name}</li>
)
}
</ul>
}
}
Redux is just another way of doing this that enables better reuse of information, and makes that same information available to different components (hiding the instance of the "store" as a mixin). That MyApp class on top of your structure serves a similar function to the Provider class in redux: allowing child components to access information needed to display themselves.