I created a new react-native project recently, and I found the component syntax becoming export default class WelcomeScreen extends Component<Props> that's different from export default class WelcomeScreen extends Component before.
I thought it's replace the syntax of code of below
constructor(props) {
super(props)
}
but after testing, I found I still have to ref props with the code above, so what's the exactly function of this syntax <Props> ?
Component<Props> is syntax of Flow to check type of data on Props. Flow infers types and tracks data as it moves through your code.
Example:
// #flow
import * as React from 'react';
import { Text } from 'react-native';
type Props = {
bar: string, // this mean type data of bar is string and is required.
};
class MyComponent extends React.Component<Props> {
render() {
return <Text>{this.props.bar}</Text>;
}
}
Reference:
https://flow.org/en/
https://flow.org/en/docs/react/
Related
I wrote a BaseListPage component like this:
export default class BaseListPage extends Component<Props, State> {
and, I want to write another component inherited BaseListPage, like this:
export default class DynamicListPage extends BaseListPage<Props, State> {
but it prompts Type 'BaseListPage' is not generic..
I'm a new typescripter in react-native, please help!
It's because you're passing type arguments to your BaseListPage class with the BaseListPage<Props, State> part of class DynamicListPage extends BaseListPage<Props, State>, but the class doesn't accept any type arguments.
You can let BaseListPage take type arguments by making it a 'generic':
class BaseListPage<Props, State> extends Component<Props, State> {
see - https://www.typescriptlang.org/docs/handbook/generics.html
Since a react component could have any shape of props or state, those type arguments allow you to define exactly what they will look like for a given instance of a class, allowing you to run the necessary type checks.
Eg.
interface Props {
foo: string
}
class MyComponent extends Component<Props> {
render() {
console.log(this.props.foo) // Fine
console.log(this.props.bar) // Error
...
}
}
So either, define the exact Props and State that a BaseListPage component can have like so, thereby removing the need for it to be generic:
interface BaseListPageProps {
foo: string
}
interface BaseListPageState {
bar: string
}
class BaseListPage extends Component<BaseListPageProps, BaseListPageState> {
...
}
class DynamicListPage extends BaseListPage {
render() {
console.log(this.props.foo) // Fine
console.log(this.state.bar) // Fine
console.log(this.props.bar) // Error
...
}
}
or let it be generic, allowing the DynamicListPage to decide the Props and State types:
class BaseListPage<Props, State> extends Component<Props, State> {
...
}
interface DynamicListPageProps {
foo: string
}
interface DynamicListPageState {
bar: string
}
class DynamicListPage extends BaseListPage<DynamicListPageProps, DynamicListPageState> {
Better yet, compose via composition, not inheritance. https://reactjs.org/docs/composition-vs-inheritance.html
Use
export default class DynamicListPage extends BaseListPage {
instead of
export default class DynamicListPage extends BaseListPage<Props, State> {
That should be enough to make your code work as you expected.
More info about this topic can be found here: https://www.typescriptlang.org/docs/handbook/generics.html
I want to build a super class which contains several methods cause I want to call them from different classes. Furthermore, I have the benefit of reducing code.
However, I get the error message "Super expression must either be null or a function"
This is one of my classes where I want to call the function super.interface() from the SuperScreen.js file:
import React from "react";
import { SuperScreen } from "./SuperScreen";
export default class HomeScreen extends SuperScreen {
constructor(props) {
super(props);
this.state = {
isLoading: true,
data: null,
key: 15
};
}
render() {
return super.interface();
}
}
My SuperScreen.js
import React, { Component } from "react";
export default class SuperScreen extends Component {
constructor() {}
interface() {...}
}
However, I still get the message Super expression must either be null or a function. Why and how can I fix it?
Kind regards and Thank You
Your import is a bit messed up.
Remove the curly brackets from SuperScreen import because you exported SuperScreen class as default.
import SuperScreen from "./SuperScreen";
Or correct the export instead
export class SuperScreen extends Component
I am writing a class in React and exporting it with a higher order component, presently I have ...
import React, { Component } from 'react';
import { withRouter } from 'react-router';
/**
Project Editor
*/
class SpiceEditorRaw extends Component { ... }
const SpiceEditor = withRouter(SpiceEditorRaw);
export default SpiceEditor;
Then In a different file I import SpiceEditor and subclass it with
import SpiceEditor from './SpiceEditor'
class NameEditor extends SpiceEditor {
constructor(props){ ... }
...
render () { return (<h1> hello world <h1/>) }
}
However I am getting error:
index.js:2178 Warning: The <withRouter(SpiceEditorRaw) /> component appears to have a render method, but doesn't extend React.Component. This is likely to cause errors. Change withRouter(SpiceEditorRaw) to extend React.Component instead.
I believe it is possible to create a compoenent using withRouter, so I must be syntaxing incorrectly?
You should generally not use extends on any other component than React.Component. I think the Composition vs Inheritance part of the documentation is a great read on this subject.
You can accomplish almost everything with composition instead.
Example
import SpiceEditor from './SpiceEditor'
class NameEditor extends React.Component {
render () {
return (
<SpiceEditor>
{ /* ... */ }
</SpiceEditor>
)
}
}
Has anyone tried using the React Component library? https://formidable.com/open-source/component-playground/
Is there a way to only show just a segment of the codeText in the live code editor (e.g without the class and render method) but still setting the noRender to false?
Thanks!
You can create your component and then extend it with another component with the methods and properties you want to show.
For example;
export default class PrivateComponent extends React.Component {
constructor(props) {
super(props);
// constructor logic here
}
someHiddenMethod() {
// ...
}
render() {
return(
<div>
<h1>Hidden Render</h1>
</div>
)
}
}
import PrivateComponent from './PrivateComponent.jsx';
export default class PublicComponent extends PrivateComponent {
somePublicMethod() {
// ...
}
}
I'm using ES6 classes with Babel. I have a React component that looks like this:
import { Component } from 'react';
export default class MyReactComponent extends Component {
getInitialState() {
return {
foo: true,
bar: 'no'
};
}
render() {
return (
<div className="theFoo">
<span>{this.state.bar}</span>
</div>
);
}
}
It doesn't look like getInitialState is being called, because I'm getting this error: Cannot read property 'bar' of null.
The developers talk about ES6 class support in the Release Notes for v0.13.0. If you use an ES6 class that extends React.Component, then you should use a constructor() instead of getInitialState:
The API is mostly what you would expect, with the exception of getInitialState. We figured that the idiomatic way to specify class state is to just use a simple instance property. Likewise getDefaultProps and propTypes are really just properties on the constructor.
Code to accompany Nathans answer:
import { Component } from 'react';
export default class MyReactComponent extends Component {
constructor(props) {
super(props);
this.state = {
foo: true,
bar: 'no'
};
}
render() {
return (
<div className="theFoo">
<span>{this.state.bar}</span>
</div>
);
}
}
To expand a bit on what it means
getDefaultProps and propTypes are really just properties on the constructor.
the "on the constructor" bit is weird wording. In normal OOP language it just means they are "static class variables"
class MyClass extends React.Component {
static defaultProps = { yada: "yada" }
...
}
or
MyClass.defaultProps = { yada: "yada" }
you can also refer to them within the class like:
constructor(props) {
this.state = MyClass.defaultProps;
}
or with anything you declare as a static class variable. I don't know why this is not talked about anywhere online with regards to ES6 classes :?
see the docs.