I am still on the way of the conquest React. I prefer to use a es6 component-based approach when creating React classes. And I detained at the moment when it is necessary to inheritance of some existing class with already defined defaultProps static property.
import {Component} from 'react';
class MyBox extends Component {
}
// Define defaultProps for MyBox
MyBox.defaultProps = {
onEmptyMessage: 'Nothing at here'
}
When I define a static property defaultProps of class that extend MyBox, it completely overwrites defaultProps of parent class.
class MyItems extends MyBox {
render() {
// this.props.onEmptyMessage is undefined here
// but this.props.onRemoveMessage is present
return <i>{this.props.onEmptyMessage}</i>; //<i></i>
}
}
// Define defaultProps for MyItems
MyItems.defaultProps = {
onRemoveMessage: 'Are you sure?'
}
But i need to extend defaultProps of parent class, not overwrite. I understand that is possible by extending directly defaultProps property of parent class.
MyItems.defaultProps = _.extend(MyBox.defaultProps, {
onRemoveMessage: 'Are you sure?'
});
But i think that such trick is dirty. Is there a way to perform it according to React plan?
In my opinion you the issue is not how you can merge the properties but how you can compose it without extending. You would have your components like this:
class MyBox extends Component {
static defaultProps = { title: 'Box title' }
render() {
return (
<div className={'mybox ' + this.props.className}>
<h1>{this.props.title}</h1>
{this.prop.children}
</div>
)
}
}
class MyItems extends Component {
render() {
return (
<MyBox className="itembox" title="Items title">
<i>{this.props.children}</i>
</MyBox>
)
}
}
Then use it like that
<MyBox>
box
</MyBox>
or
<MyItems>
items box
</MyItems>
That will render:
<div class="mybox">
<h1>Box title</h1>
box
</div>
or
<div class="mybox itembox">
<h1>Items title</h1>
<i>items box</i>
</div>
It looks like you have extending/overriding the className or the title, but you have composed. If you use this way of building your UI, you'll see it will be easier and faster
Related
I understand sub classing with extends for example
class Car extends Vehicle {}
class Dog extends Animal {}
But with React, you may see
class HelloMessage extends React.Component {}
What does the dot between React and Component mean? How does it work in React and in vanilla Javascript?
Classes do not have to be standalone variable names - they may be properties of objects as well. So extends React.Component, absent any other context of what React is, just means that React is an object with has a Component property which is a class.
For an example of how to emulate this in vanilla JS:
const obj = {
Foo: class Foo {
doThing() {
console.log('doing thing');
}
}
};
class MySubClass extends obj.Foo {
subMethod() {
console.log('submethod');
}
}
const s = new MySubClass();
s.doThing();
s.subMethod();
React is doing the same sort of thing. It's just a way to organize data as properties of objects.
I was into functional Javascript previously, Recently I started with Object oriented Javascript and React Library. This question is more of understanding the code.
Why below code don't work
class MyComponent extends React.Component{
propTypes : {
name: React.PropTypes.string.isReequired,
location: React.PropTypes.string
}
render(){
return(
<h1>Hello This is {this.props.name} and I live in
{this.props.location}</h1>
);
}
}
ReactDOM.render(
<MyComponent name="Node" location="DOM"/>,
document.getElementById('root')
);
Whereas this code works,
class MyComponent extends React.Component{
render(){
return(
<h1>Hello This is {this.props.name} and I live in {this.props.location}</h1>
);
}
}
MyComponent.propTypes = {
name: React.PropTypes.string.isReequired,
location: React.PropTypes.string
}
ReactDOM.render(
<MyComponent name="Node" location="DOM"/>,
document.getElementById('root')
);
Can someone help me understand this? Thanks.
You need to use static word (to define the static property) because, propTypes need to be declared on the class itself, not on the instance of the class , and use =.
Check the DOC.
Like this:
static propTypes = {
name: React.PropTypes.string.isRequired,
location: React.PropTypes.string
}
Inside an ES6 class, static properties look like this
class X extends Y {
static staticThing = {
...
}
}
note the =
"assigning" a static property the ES5 way looks like the second way you have it there
Typically, you'll use the second way for functional components whereas you might as well use the first way (albeit properly with an =) for ES6 style class components.
also, make sure you have your React.PropTypes correct - isReequired should be isRequired
I'm extending a base class and overriding a method in the base class. But when I call it, it calls the super class version. How do I override the method?
var Hello = React.createClass( {
getName: function() { return "super" },
render: function() {
return <div>This is: {this.getName()}</div>;
}
});
class HelloChild extends Hello {
constructor(props) {
super(props);
console.log( this.getName());
}
getName()
{
return "Child";
}
};
I want it to print "This is: Child" but it prints "This is: super"
The problem is that you're mixing ES6 type class declaration (ex. Hello) with old school Javascript declaration (ex. HelloChild). To fix HelloChild, bind the method to the class.
class HelloChild extends Hello {
constructor(props) {
super(props);
this.getName = this.getName.bind(this); // This is important
console.log( this.getName());
}
getName()
{
return "Child";
}
};
Then it'll work.
I found the answer (adapted from here: https://gist.github.com/Zodiase/af44115098b20d69c531 ) - the base class needs to also be defined in an ES6 manner:
class Hello extends React.Component {
//abstract getName()
getName()
{
if (new.target === Hello) {
throw new TypeError("method not implemented");
}
}
render() {
return <div>This is: {this.getName()}</div>;
}
};
Actually you can override method to execute code from your subclass
class Hello extends React.Component {
getName() {
super.getName();
}
}
class HelloChild extends Hello {
getName()
{
return "Child";
}
}
Please note that this answer proposes different approach:
I wonder why you should do this in the first place, my point is that directly coupling two react components is not a right way to implement re-usability in React.
If you are trying to have multiple child components which extends one parent, What I would do is, to have child components and a higher-order component and then implement common functionality with Composition. This way you can skip those methods, which you were trying to override and so everything would stay clear.
I would like to add <p> tag in ExtendedComponent by calling super.render(), Problem is I don't know whether it is possible to modify already defined jsx object. Ideal would be to just write parentTemplate + <p>Some paragraph</p>, but that doesn't work.
class BaseComponent extends React.Component {
get title() {
return 'I am base component';
}
render() {
return <h1>Hello {this.title}</h1>;
}
}
class ExtendedComponent extends BaseComponent {
get title() {
return 'I am extended component';
}
render() {
var parentTemplate = super.render();
// append <p>Some paragraph</p> to parentTemplate
return parentTemplate;
}
}
ReactDOM.render(
<ExtendedComponent />,
document.getElementById('test')
);
Like azium mentioned in the comments, this is not common to do with react. However, if you need to do it, it can be accomplished like this:
render() {
var parentTemplate = super.render();
// append <p>Some paragraph</p> to parentTemplate
return <div>{parentTemplate}<p>Some paragraph</p></div>;
}
You have to wrap it inside a div since a react element only can return one element, not a list of them. parentTemplate is just like any other jsx, but it's in a variable. You use the {variableName} syntax to add variables into the JSX.
Another way to do this, which is more "react"-like:
class BaseComponent extends React.Component {
render() {
return <h1>Hello {this.props.title}</h1>;
}
}
BaseComponent.propTypes = {
title: React.PropTypes.string
};
BaseComponent.defaultProps = {
title: 'I am base component'
};
class ExtendedComponent extends React.Component {
render() {
return (
<div>
<BaseComponent title="I am extended component"/>
<p>Some paragraph</p>
</div>
);
}
}
ReactDOM.render(
<ExtendedComponent />,
document.getElementById('test')
);
JSFiddle
Here ExtendedComponent is a higher-order component rather than one that inherits from BaseComponent. Most of the time this is a seperation of concerns that is easier to reason about, and most react apps are built this way rather than on inheritation.
Hope this helps!
Going through the TodoMVC example of Redux I have found this unusual example of class inheritance. The class Header is probably extending React.Component as per usual (as should all React components, right?), but it is not explicitly stated in the code. What am I missing? How does this code work?
import React, { PropTypes } from 'react';
import TodoTextInput from './TodoTextInput';
export default class Header {
static propTypes = {
addTodo: PropTypes.func.isRequired
};
handleSave(text) {
if (text.length !== 0) {
this.props.addTodo(text);
}
}
render() {
return (
<header className='header'>
<h1>todos</h1>
<TodoTextInput newTodo={true}
onSave={::this.handleSave}
placeholder='What needs to be done?' />
</header>
);
}
}
If you don't need the methods defined by ReactComponent (setState() and forceUpdate()) you don't have to inherit from it.
As such, it isn't an example of class inheritance or magic because neither is happening here :)