Does the statics object work with ES6 classes in React?
class SomeComponent extends React.Component {
render() {
// ...
}
}
React.statics = {
someMethod: function() {
//...
}
};
Something like the above gives me undefined method someMethod when I do SomeComponent.someMethod()
statics only works with React.createClass. Simply declare the method as a static class method:
class SomeComponent extends React.Component {
static someMethod() {
//...
}
render() {
// ...
}
}
Regarding
React.statics = { ... }
You are literally creating a statics property on the React object. That property does not magically extend your component.
Although statics only works for React.createClass, you can still write static methods in ES6 notation. If you are using ES7, then you can also write static properties.
You can write statics inside ES6+ classes this way:
class Component extends React.Component {
static propTypes = {
...
}
static someMethod(){
}
}
Or outside the class like this:
class Component extends React.Component {
....
}
Component.propTypes = {...}
Component.someMethod = function(){....}
If you want to write it like the former, then you have to set stage: 0 on Babel (since its experimental).
Statics can be accessed without having to instantiate a component. Normally they aren't that useful but there are a few special cases. For example into routing when you leave the current page with doing a ACTION PERFORM then through Statics methods you can hold/ASKED the user whether he really want to leave the page.
For example:
exampleComponent= React.createClass({
statics:{
willTransitionFrom: function(transition,component){
// check any state here or value Aasked the user.
}
}
});
It exposes willTransitionTo and willTransitionFrom lifecycle methods. both are particular is useful as a static as you can actually cancel a transition before instantiating a component.
Stop. Just declare a class without extending React.Component and it will works.
class YourStaticClass {
static YourMethod(){
}
}
export default YourStaticClass;
in the other classes,
You can simply import your class and trigger the function
import YourStaticClass from "whatever";
...
YourStaticClass.YourMethod();
...
statics works only for React components, check docs.
Related
I know the title is maybe a bit confusing. Here's a code sample:
//First.js
export default class First extends React.Component {
constructor(props) {
super(props);
module.exports.push = route => {
this.refs.router.push(route)
}
module.exports.pop = () => {
this.refs.router.pop()
}
}
render() {
return <Router ref="router"/>
}
}
and then
//second.js
import { push, pop } from "first.js"
//class instantiation and other code
push("myRoute")
Code pen: https://codepen.io/Stefvw93/pen/bLyyNG?editors=0010
The intent is to avoid using the withRouter function from react-router. So instead, expose push/pop history functions from a single instance of react-router's browserRouter component. It works by creating a reference to the router instance (ref="router") and then exporting this instance by doing something like module.exports.push=this.refs.router.push
Since you can not declare any dynamic exports, the only way would to export push and pop would be to export some sort of mutable container object first, and then modify it afterwards. e.g Export immediately an empty object, and set its push and pop properties in the constructor.
//First.js
export const router = {};
export default class First extends React.Component {
constructor(props) {
super(props);
router.push = route => {
this.refs.router.push(route)
};
router.pop = () => {
this.refs.router.pop()
};
}
render() {
return <Router ref="router"/>
}
}
and then
//second.js
import { router } from "first.js"
//class instantiation and other code
router.push("myRoute")
But there are big downsides of doing it this way:
you’ll end up using last rendered router instance
there’s no checking if such instance already exists
you can not have multiple routers using the same pattern
I’d prefer being explicit and writing withRouter wherever I need router, because:
it is not subject to race conditions — you either have a router or you don’t, in which case you get a nice error log
it communicates your intention clearly, and documentation about withRouter exists
uses well—known and elegant HoC pattern
allows you to have multiple routers
Long story short, mutable global state is bad, just don’t do it.
This issue is only reproducable in babel (using babel-runtime-6.26.0).
Having the following structure
class Foo extends React.Component {
// ...
}
class Bar extends React.Component {
render() {
return this.props.component();
}
}
// somewhere:
<Bar component={Foo} />
worked and works for me in general, but when switching to babel I get the error message:
TypeError: Cannot call a class as a function in (classCallCheck.js:7). I've read that this is spec compliant behavior, but it does work outside of the babel environment.
Btw, if I use functional stateless components it works, of course. But I can't guarantee that the consumer of my lib is providing such a component and not a class based one.
How can I approach this using babel?
Is there a different pattern to use to pass components via properties? I believe it's common practice to pass in classes/class constructors via props to components.
A component can be either a function or a class. And ES6 classes cannot be called without new, at least the ones that are spec-compliant (this includes native and Babel classes).
This is not a problem since components shouldn't be instantiated manually. Both function and class components will be properly handled by ReactDOM.render:
class Bar extends React.Component {
render() {
const Component = this.props.component;
return <Component/>;
}
}
Try using React.createElement(this.props.component, props) instead.
Here's a working example:
class Foo extends React.Component {
render() { return "Foo" }
}
class Bar extends React.Component {
render() {
return React.createElement(this.props.component, {})
}
}
ReactDOM.render(
<Bar component={Foo} />,
document.getElementById('root')
);
https://codepen.io/anon/pen/QQGQYZ
I'm looking through the React documentation and I've come across this code.
import PropTypes from 'prop-types';
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
Greeting.propTypes = {
name: PropTypes.string
};
Is there a specific name for what they are doing here, where they are creating an object of propTypes on the class?
Is this just a React thing or can this be done in any ES6 code?
Why can't we just set a variable of propTypes within the class itself, why does it have to come outside the class?
That's because propTypes is a static1 property of the class, not associated with a certain instance of the class but the class itself. React's prop type-checking looks for propTypes of a certain component as a static property of the component's class. It's not on the class's prototype, but on the class itself.
If you were to declare it inside the class, it would be an instance property:
class Greeting extends React.Component {
get propTypes() { //Not static!
...
}
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
Every Greeting component would then have the property propTypes and React won't properly type-check the props. You could use a static getter and declare it as a static property of the class though:
static get propTypes() {
...
}
The reason it's outside the class is based on preference. Static properties and getters can be used anywhere in ES2015 (or ES6) code.
In future versions of ECMAScript you can declare class properties. You can use class properties now with Babel and the transform-class-properties plugin (also in the stage-2 preset):
class Greeting extends React.Component {
static propTypes = {
...
}
}
This is syntactic sugar and works exactly the same as the static getter acting as a static property of the class.
1 Static meaning "unchanging" because the property doesn't change based on instance, it's the same across all instances because it's not associated with just one instnace.
PropTypes is a React specific API. It's a way that o tell React to perform basic runtime type-checking of the properties you pass to a component. In your example, you are saying that Greeting components can take a name property of type string, but it's not required.
The way that this special propTypes property is defined is not specific to React, though, it's just an ES6 static class property. It's a property associated with the class declaration itself (Greeting.propTypes), not instances of the class (new Greeting().propTypes is undefined). There's actually a newer ES7+ syntax you can use which is equivalent:
class Greeting extends React.Component {
static propTypes = {
name: PropTypes.string
};
render() { }
}
console.log(Greeting.propTypes) // { name: ... }
You declare / define a class and you instantiate objects of a certain class.
I'm encapsulating a Menu called JellMenu, and I want to expose CustomMenuItem like JellMenu.Item instead of import CustomMenuItem. I have no idea how to do.
I took look at react-native-viewpager source code, and I think this maybe helpful:
var ViewPager = React.createClass({
statics: {
DataSource: ViewPagerDataSource,
},
It will expose ViewPagerDataSource as ViewPager.DataSource, right? I don't know exactly. what's the meaning of the keyword statics in Es5, and what's the alternative in Es6? Thank you in advance.
It isn't a keyword, it's just a property name in an object initializer being passed to React.createClass. From the documentation, it's used to specify static (non instance-specific) parts of a React class:
The statics object allows you to define static methods that can be called on the component class.
Although statics only works for React.createClass, you can still write static methods in ES6 notation. If you are using ES7, then you can also write static properties.The statics object allows you to define static methods that can be called on the component class. For example:
var MyComponent = React.createClass({
statics: {
customMethod: function(foo) {
return foo === 'bar';
}
},
render: function() {
}
});
MyComponent.customMethod('bar'); // true
Methods defined within this block are static, meaning that you can run them before any component instances are created, and the methods do not have access to the props or state of your components. If you want to check the value of props in a static method, have the caller pass in the props as an argument to the static method.
Also, You can write statics inside ES6+ classes this way:
class Component extends React.Component {
static propTypes = {
...
}
static someMethod(){
}
}
Or outside the class like this:
class Component extends React.Component {
....
}
Component.propTypes = {...}
Component.someMethod = function(){....}
I've seen many tutorials with code that suggests doing something like the following:
var App = React.createClass({
someFunction() { .. },
render() { return(); },
});
var Lication = React.createClass({
someOtherFunction() { .. },
render() { return(); },
});
...but I've been using the ES6 syntax:
class App extends Component {
someFunction() { .. }
render { return(); }
}
Where do I create the Lication class? Right below the App class? Or does it need its own file, and imported into the main file with something like:
var Lication = require('./Lication');
I have yet to see code that uses multiple classes.
Where do I create the Lication class? Right below the App class? Or does it need its own file?
Using ES6 classes or React's createClass function makes no rules about where you have to define them. Both can be defined one above another or in different files.
The one way using ES6 classes does affect code order is with hoisting:
An important difference between function declarations and class declarations is that function declarations are hoisted and class declarations are not. You first need to declare your class and then access it.
Which means something like this is invalid:
var l = new Lication(); // ReferenceError
class Lication {}
As far as splitting the code into files or not, this is valid:
class App extends React.Component {
// ...
}
class Lication extends React.Component {
// ...
}
And so is this:
class App extends React.Component {
// ...
}
var Lication = require('path-to-lication-class');
Where Lication would be defined in its own file and exported out:
class Lication extends React.Component {
// ...
}
module.exports = Lication;
The last example is essentially equivalent to:
class App extends React.Component {
// ...
}
var Lication = class Lication extends React.Component {
// ...
}
Splitting into files is done to achieve modularity in your code, where individual components are split into files (or modules) so they can be easier to maintain and the whole app isn't crowded into one giant file while developing but combined later when deploying.
Here's a useful read on classes