I am new to React and was learning propTypes and the ways to implement them in React. One of the ways of propType implementation is via class fields, that is,
class Foo extends React.Component {
static PropTypes = {};
}
The question is why need to use static for propTypes and is it ok to omit static? I really hope for your beginner-friendly explanation since I have looked through the answer here react: why static propTypes but did not properly understand WHY?
Static props are those that belong to the class, not to an instance. This means that one class is shared throughout the entire application. This is known as the singleton pattern. The reason you would do this is because propTypes do not belong to a single instance, as mentioned in the question you linked. propTypes are used for type checking the props passed in, so there is no need for them to be tied to specific instances:
https://blog.logrocket.com/validating-react-component-props-with-prop-types-ef14b29963fc/
It is not OK to omit static, because the PropTypes library is expecting a class property when it looks for your prop definitions. If you omit static, you are defining an instance property, which is not how the library operates. Omitting the keyword will result in an instance property and your props will not be validated as expected.
If the static keyword is confusing, just think of it as doing the same exact thing as the following:
class Foo extends React.Component {
static propTypes = {}
}
// equivalent to
class Foo extends React.Component {}
Foo.propTypes = {}
Related
This is part ES6 question part React question. I'm trying to use namespaced components in React with ES6 classes and Babel. So I guess the real question is how to name space es6 classes so I can do what is explained here: https://facebook.github.io/react/docs/jsx-in-depth.html#namespaced-components
Since I get an unexpected token error:
class Headline extends Component { ... }
class Headline.Primary extends Component { ...
^
The ECMAScript-6 class declaration syntax expects a standard BindingIdentifer as the class name. A dot is not a valid character inside an identifier name.
In the context used in the link in OP, the "namespace" is an object, and properties are added to that object one by one using the dot notation for property access.
You could replicate that by using a class expression instead:
'use strict'
var ns = {}
ns.MyClass = class {
constructor() {
console.log('in constructor')
}
}
new ns.MyClass()
This doesn't really change with ES6, you still will have to do an assignment:
Headline.Primary = class Primary extends Component { … };
However, using classes like Headline as namespaces is getting pretty deprecated with ES6 (and has previously been a questionable practice anyway), you should instead leverage the new module system. Export Primary as a named export, and instead of importing the Headline class rather do import * as headlines from ….
This link also relates to this question.
In the Module objects section, it is described that you can do something like this:
// headline.js file
export {Headline, Primary}
class Headline {}
class Primary {}
// In another module...
import * as Headline from "headline";
let h = new Headline.Headline();
let hp = new Headline.Primary();
It's not exactly what you are trying to do, but is an alternative.
Another way of doing it is almost like #Bergi has already pointed out, but I'm just clarifying it further:
let Headline = class Headline extends Component { }
Headline.Primary = class Primary extends Component { }
export {Headline as default}
// in another module:
import Headline from 'headline';
let headline = new Headline();
let primary = new Headline.Primary();
I'm trying to figure out how to write a type definition for react-highlight (class Highlightable, see here) in order to extend Highlightable and add custom functionality. Since the original Highlightable JS-class is a subclass of React.Component, I also need to have all the methods of React.Component available in my type definition. What's the best way of solving this?
This is using NPM and webpack. I'm following this tutorial.
I try to import and use the component like this:
import {Highlightable} from "highlightable";
then:
<Highlightable
enabled={true}
highlightStyle={{
...
My goal is to be able to say:
class MyHighlightable extends Highlightable { ...}
and overwrite methods. That's why I want a type definition.
I managed to get a simple Import working by adding declare module "highlightable"; to a index.d.ts file in src/#types/highlightable.
When I now try to add a class definition like this:
declare module "highlightable" {
export class Highlightable {
}
}
Typescript of course complains about the missing methods from the React.Component superclass:
TS2607: JSX element class does not support attributes
because it does not have a 'props' property.
So when extending with an empty class body export class Highlightable extends React.Component<T,T> {, in index.d.ts and adding method defintions, etc. everything compiles but I get this error at runtime:
Uncaught Error: Element type is invalid: expected a string (for
built-in components) or a
class/function (for composite components) but got: undefined.
Outputting the Highlightable import to console confirms it's undefined.
Copy and pasting method definitions from a React type definition on Definately typed doesn't help either (still undefined).
How can I solve this and provide a type definition for a subclass? If it is not possible, how can I work around it?
Solved, inspired by this post. My typedefinition now looks like this:
declare namespace HighlightableNs {
class Highlightable extends React.Component<any, any> {
}
}
declare module "highlightable" {
export default HighlightableNs.Highlightable;
}
When subclassing, I use the default import:
import Highlightable from "highlightable";
export class HighlightableColorMarked extends Highlightable {
The custom class can now be imported normally:
import {HighlightableColorMarked} from "./wordselection/HighlightableColorMarked";
If anyone knows why this is necessary or has a more elegant solution, feel free to post.
I created a new React Native project using react-native init and in the generated template, the main component class looks like this:
export default class App extends Component<{}> {
...
}
I don't really understand what the <{}> part means. I've never seen this before and all the examples seem to omit it. Just curious as to what its purpose is and if it's necessary.
When you are using typescript, you have to specify the type of values to be expected. This allows detecting mismatching properties during compile time and reduces the amount of errors.
So when you do Component<{}>, {} is the type for Props, your component will receive.
This is how React's Component class looks like:
If you notice, the type is <P, S>, which stands for <Props, State>.
There is another interface called ComponentClass that has a signature <P>,
which initializes a new component internally with state as any. This interface is used in ReactElement's type:
So all in all, you are defining a Component which accepts no props and but can have state of any type. This is usually done when you are not sure about you component's interactions.
Ideally a component should look like this:
interface IComponentState {
...
}
interface IComponentProps {
...
}
export class MyComponent<IComponentProps, IComponentState> extends React.Component {
...
}
This enforces consumer to pass any necessary properties and enforces you to have proper value of state.
This is either Typescript of Flow. You usually don't describe props as propTypes, but rather as interface or type. Then the type is passed to React.Component as a generic.
Type of props would be the passed type plus { children?: ReactNode }
Actually there are two generic arguments, second for State
Very useful and convenient stuff.
https://www.typescriptlang.org/docs/handbook/generics.html
https://www.typescriptlang.org/docs/handbook/react-&-webpack.html
These are flow type annotations. See https://flow.org/
You'll notice that there's a #flow comment at the top of the file, and a .flowconfig file in the root of the project.
Using flow here is optional, but it can help you catch bugs.
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(){....}