I was looking through the React documentation and ran into the static method. I Was wondering in what sort of scenario it might be useful and couldn't think of any.
Is there a specific scenario in which static methods are useful when building components in React?
defaultProps and propTypes are static members of React components, they do not change for every instance. See https://facebook.github.io/react/docs/reusable-components.html
One example for static properties is to be able to track how many instances of an object were created (not React specific). Note that most of the time, static methods are a code smell if you are modifying state.
var Contacts = React.createClass({
statics: {
instanceCount: 0
},
getInitialState: function() {
Contacts.instanceCount++
return {};
},
render: function() {
return (<div > Hello {
this.props.name
} < /div>);
}
});
console.log(Contacts.instanceCount) // 0
ReactDOM.render( < Hello name = "World" / > ,
document.getElementById('container')
);
console.log(Contacts.instanceCount) // 1
Another example is a way to store constants.
var Contacts = React.createClass({
statics: {
MAX_VALUE:100
},
render: function() {
return (<div > Hello {
this.props.name
} < /div>);
}
});
if (someValue > Contacts.MAX_VALUE) {
}
Related
I am using ReactDOM.render() to render a component I have created. The component is fairly complicated, due to the specifics of the implementation, but I can easily render it iff I avoid using JSX syntax. However, if I use JSX, I cannot render the component at all and I get the following error:
TypeError: _this2.props.children.forEach is not a function
My code can be seen below (I also get a few warnings that I haven't gotten around to fixing yet, so you can just ignore those for the time being). Bear in mind that the structure of the HTML for the component is very strict (due to the CSS framework I'm using) and cannot be changed. Is there a way to use JSX for achieving the same result and, if so, what is it that I'm doing wrong?
// This function was based on this answer: https://stackoverflow.com/a/10734934/1650200
function generateUniqueId() {
// always start with a letter (for DOM friendlyness)
var idstr = String.fromCharCode(Math.floor((Math.random() * 25) + 65));
do {
// between numbers and characters (48 is 0 and 90 is Z (42-48 = 90)
var ascicode = Math.floor((Math.random() * 42) + 48);
if (ascicode < 58 || ascicode > 64) {
// exclude all chars between : (58) and # (64)
idstr += String.fromCharCode(ascicode);
}
} while (idstr.length < 32);
return (idstr);
}
// Technically this is not exactly a component, but I use it as such to make things simpler.
class Tab extends React.Component {
render() {
return React.createElement('div', {}, this.props.children);
}
}
// This is my Tabs component
class Tabs extends React.Component {
// In the constructor, I take all children passed to the component
// and push them to state with the necessary changes made to them.
constructor(props) {
super(props);
var state = {
group: 'tab_group_' + generateUniqueId(),
children: []
}
this.props.children.forEach(
function(child) {
if (!child instanceof Tab) {
throw "All children of a 'Tabs' component need to be of type 'Tab'. Expected type: 'Tab' Found Type: '" + child.class + "'";
return;
}
var tab = Object.assign({}, child);
tab.internalId = 'tab_' + generateUniqueId();
state.children.push(tab);
}
);
this.state = state;
}
// When rendering, I don't render the children as needed, but I create
// the structure I need to use for the final result.
render() {
var childrenToRender = [];
var groupName = this.state.group;
this.state.children.forEach(function(tab) {
childrenToRender.push(
React.createElement(
'input', {
type: 'radio',
name: groupName,
id: tab.internalId,
checked: true,
'aria-hidden': 'true'
}
)
);
childrenToRender.push(
React.createElement(
'label', {
'htmlFor': tab.internalId,
'aria-hidden': 'true'
},
'demo-tab'
)
);
childrenToRender.push(React.createElement('div', {}, tab.props.children));
});
return React.createElement('div', {
'className': 'tabs'
}, childrenToRender);
}
}
// This works fine
ReactDOM.render(
React.createElement(Tabs, {}, [React.createElement(Tab, {}, 'Hello world')]),
document.getElementById('root')
);
// This fails with the error mentioned above
// ReactDOM.render(
// <Tabs>
// <Tab>Hello, world!</Tab>
// </Tabs>,
// document.getElementById('root')
// );
<link rel="stylesheet" href="https://gitcdn.link/repo/Chalarangelo/mini.css/master/dist/mini-default.min.css">
<script src="https://unpkg.com/react#latest/dist/react.js"></script>
<script src="https://unpkg.com/react-dom#latest/dist/react-dom.js"></script>
<script src="https://unpkg.com/babel-standalone#6.15.0/babel.min.js"></script>
<div id="root"></div>
Update: This only happens if I actually pass only one <Tab> to the <Tabs> due to the way it's processed. If, for example, I use the following code, I can use JSX to render the component and its contents:
ReactDOM.render(
<Tabs>
<Tab>Hello, world!</Tab>
<Tab>Hello, world!</Tab>
</Tabs>,
document.getElementById('root')
);
After checking out what babel output from the JSX code, I realized that it was not ouputting something like [React.createElement(Tab, {}, 'Hello world')] but rather something more like React.createElement(Tab, {}, 'Hello world'), meaning it was not an array, thus causing problems with .forEach().
To anyone interested, what I did was check if this.props.children is an array and, if not, to actually turn it into one. Sample below:
if (!Array.isArray(this.props.children))
var tempProps = [this.props.children];
else
var tempProps = this.props.children;
tempProps.forEach(
// Rest of the code is pretty much the same as before
);
This is not a very elegant solution, so feel free to post more elegant answers if you know any.
I am currently trying to figure out a way to assign methods to the super object in a class, in order to extend a functionality inside a class.
I want to create a "Component" class and have each class that extends the "Component" class have different methods depending on the component needs. I want to use the term "describe" for the method that would extend the super object. Therefore, I am describing the component.
Here is an example:
class Component {
constructor (args) {
this.template = args.template;
}
getTemplate () {
return this.template;
}
describe () {
//The magic should happen here
}
}
Class Controller describer
class Controller {
constructor () {
}
getEvents () {
return {};
}
}
Extending the Component class.
Then, using the "describe" method to inject other methods from other classes.
class example extends Component {
constructor () {
super({template: '<div></div>'});
super.describe({
Controller
});
super.getTemplate();
super.getEvents();
}
}
var app = new App({
example
});
Is it possible? Thank you :)
I am learning React-Redux and I have an issue navigating through the objects in my JSON file. I have the following file JSON, the file is designed to render out a side navigation:
export default function(){
return [
{
catId:"parMenu1",
parentCat:"Genres",
subcat:[
{
genre:"8Bit",
genreId:"1"
},
{
genre:"Acid House",
genreId:"2"
}
]
},
{
catId:"parMenu2",
parentCat:"sounds",
subcat:[
{
genre:"blah",
genreId:"3"
},
{
genre:"blah House",
genreId:"4"
}
]
]
}
I have the JSON file mapped to state props for a component. The component looks like so:
class BrowseByCont extends Component {
render () {
return (
<div className="browseByContInner">
{
console.log(this.props.reducerSidenav[0].catId)
}
</div>
)
}
}
function mapStateToProps(state) {
return {
reducerSidenav:state.reducerSidenav
};
}
I am trying to reach the subcats object within the parent object. The JSON object is linked to a variable called "reducerSidenav". So far I have managed to get this far into my JSON file: this.props.reducerSidenav[0].catId. this spits out the value parMenu1 which is the "parent" object I want to target. Where I am stuck though is I am trying to achieve two things:
firstly - I would like to access the first "parent" object by without having to refer to the first item in the array: reducerSidenav[0] but rather by find the catId with a value of parMenu1. This is because this list will be dynamic in future and referring to the first array object is not reliable.
secondy - I would then like to access the subcat object and get to the value thats associated to the key genre ie to return the value "8Bit"
You can use .find() to achieve both things.
class BrowseByCont extends React.Component {
render () {
let first = this.props.reducerSidenav.find(item => item.catId === "parMenu1");
let second = first.subcat.find(subcat => subcat.genre === "8Bit")
return (
<div className="browseByContInner">
<div>{first.catId}</div>
<div>{second.genre}</div>
</div>
)
}
}
Edit
In order to print all the subcats, you have to use .map()
class BrowseByCont extends React.Component {
render () {
let first = this.props.reducerSidenav.find(item => item.catId === "parMenu1");
return (
<div className="browseByContInner">
{first.subcat.map(genreItem =>
<div key={genreItem.genreId}>{genreItem.genre}</div>)
}
</div>
)
}
}
jsfiddle
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'm trying to have a component that can find parent/child components of the same type.
These components will also have to be "repeatable" programmatically.
Such that:
<MyComponent id="1>
<div>
<MyComponent id="2">
<div>
<MyComponent id="3"></MyComponent>
</div>
<div>
<MyComponent id="4"></MyComponent>
</div>
</MyComponent>
</div>
</MyComponent>
Basically what I need, is a way to traverse the tree of MyComponents (traversal is logically controlled).
I can pass control/parameters to the parent component, or have the parent component pass control/parameters to children components in a predefined order (based on data).
I have two methods to do this, both involve preprocessors.
One is a preprocessor that generates a new Component for each MyComponent found, with some boilerplate. Something like:
var MyComponent_1 = React.createClass({
initialState: function(){ return {currentObject: 0} },
parentCallback: function(x){ /* traversal logic */ },
render: function(){
var nodes=[];
for(var i=0;i<RepeatParam;i++) nodes.push((<div><MyComponent_2 parent={parent}></MyComponent_2></div>));
return nodes;
}
});
var MyComponent_2 /** just like the above */
Another method was to add function closures, something like this:
var $parent=0, parent=0;
<div>
(function(){parent=$parent;$parent=1;
return (<MyComponent parent={parent}>
<div>
(function(){parent=$parent;$parent=2;
<MyComponent parent={parent}></MyComponent>
})()
</div></MyComponent>}))()</div>
Yet another method was to use global variables and inject them into the createClass.
All of these methods seem wrong, and as if I have a very big misunderstanding of how React should work. Is there a more elegant way to be able to traverse the tree of components, and what is the anti-pattern I am committing; how should I be doing this?
This can now be done using the "context" api
export class Hierarchy {
contextTypes: {
level: React.PropTypes.number
}
childContextTypes: {
level: React.PropTypes.number
}
getChildContext() {
return {
level: this.context.level + 1
};
}
render() {
return <div>{this.context.level}{this.children}</div>;
}
}
A combination of higher order components, contexts, and Flux makes it easier to implement.