Let's say I have an App
component whose state consists of an object whose shape is given by the following Flow type:
type Person = {
fname: string,
lname: string
};
To assert that the state of my component is indeed of type Person
I create an artificial local variable inside getInitialState
so that I can annotate the type:
const App = React.createClass({
getInitialState: function() {
const person : Person = {fname: 'John', lname: 'Doe'};
return {person: person};
}
, render: function() {
return (
<PersonDetails person={this.state.person}/>
);
}
});
The above works (even though having to declare the const person
is a minor inconvenience). The problem arises when I wish to pass that state as the property of another component. In that case, I have found no other solution but to re-define the shape of Person using React's PropTypes
API:
const PersonDetails = React.createClass({
propTypes: {
person: React.PropTypes.shape({fname: React.PropTypes.string.isRequired,
lname: React.PropTypes.string.isRequired}).isRequired
},
render: function() {
return (
<div>
<span>{this.props.person.fname}</span>
<span>{this.props.person.lname}</span>
</div>
);
}
});
This is clearly not DRY plus I am using two different methods to provide static type information (Flow and the React.PropTypes API).
Is there a way to allow the PersonDetails
component to reuse the type declaration of Person
?
The only way I have found is using proper classes (not React types):
class Person {
fname: string;
lname: string;
constructor(fname: string, lname: string) {
this.fname = fname;
this.lname = lname;
}
};
const PersonDetails = React.createClass({
propTypes: {
person: React.PropTypes.instanceOf(Person).isRequired
},
render: function() {
return (
<div>
<span>{this.props.person.fname}</span>
<span>{this.props.person.lname}</span>
</div>
);
}
});
const App = React.createClass({
getInitialState: function() {
const person : Person = new Person('John', 'Doe');
return {person: person};
}
, render: function() {
return (
<PersonDetails person={this.state.person}/>
);
}
});
export default App;
… while the above succeeds in re-using the definition it is not clear to me when I ought to use Flow types versus classes to statically type-check my components. Plus, I am not sure the two methods are really equivalent (eg in terms of being able to express null-ability of values).
Declare your type once and export it:
// types/index.js
export type Person = {|
fname: string,
lname: string,
|}
Then reuse it everywhere.
In component's state
:
// App.js
import type { Person } from './types'
type State = {|
person: Person,
|}
class App extends Component {
state: State = {
person: { fname: 'John', lname: 'Doe' },
}
render() {
return (
<PersonDetails person={this.state.person} />
)
}
}
In component's props
:
// components/PersonDetails.js
import type { Person } from '../types'
type Props = {|
person: Person,
|}
// stateful syntax
class PersonDetails extends Component {
props: Props
render() {
const { person } = this.props
return (
<div>
<span>{person.fname}</span>
<span>{person.lname}</span>
</div>
)
}
}
// stateless syntax
const PersonDetails = ({ person }: Props) => (
<div>
<span>{person.fname}</span>
<span>{person.lname}</span>
</div>
)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.