Props & State Interfaces
https://frontendmasters.com/courses/intermediate-react-v2/props-state-interfaces/
Carousel
// **** Carousel.tsx ****
import React from "react";
// **** 1. import Photo. ↴
import { Photo } from "@frontendmasters/pet";
// **** 3. add interface. ↴
// we haven't yet used interfaces...
// you have to capitalise (by convention)
interface IProps {
media: Photo[];
}
// **** 4. interface. ↴
interface IState {
active: number;
photos: string[]; // "string array"
}
// **** 5. add the IProps and Istate. ↴
class Carousel extends React.Component<IProps, IState> {
// **** 2. add public. ↴
// this actually has to match
// what's defined in
// interface IState
public state: IState = {
photos: [],
active: 0
};
// public
public static getDerivedStateFromProps({
media
// **** 6. tell what the props are. ↴
}: IProps): { photos: string[] } {
let photos = ["http://placecorgi.com/600/600"];
if (media.length) {
photos = media.map(({ large }) => large);
}
return { photos };
}
// public
// **** 7. tell the event type. ↴
public handleIndexClick = (event: React.MouseEvent<HTMLElement>) => {
// **** 8. when it's not an HTMLElement. ↴
if (!(event.target instanceof HTMLElement)) {
return;
}
// **** 9. when index not defined. ↴
// TypeScript forces you to add these defensive code checks
// that are a bit overkill
// but at least you are sure that you won't have an error here
// it's also a way of future proofing
if (event.target.dataset.index) {
this.setState({
active: +event.target.dataset.index
});
}
};
public render() {
const { photos, active } = this.state;
return (
<div className="carousel">
<img src={photos[active]} alt="animal" />
<div className="carousel-smaller">
{photos.map((photo, index) => (
// eslint-disable-next-line
<img
key={photo}
onClick={this.handleIndexClick}
data-index={index}
src={photo}
className={index === active ? "active" : ""}
alt="animal thumbnail"
/>
))}
</div>
</div>
);
}
}
export default Carousel;
Do Pet.js
// **** Pet.tsx ****
// **** 1. import what's needed . ↴
import React, { FunctionComponent } from "react";
import { Photo } from "@frontendmasters/pet";
import { Link } from "@reach/router";
// **** 3. define the interface. ↴
interface IProps {
name: string;
animal: string;
breed: string;
media: Photo[];
location: string;
id: number;
}
// **** 2. tell what FunctionComponent is. ↴
const Pet: FunctionComponent<IProps> = props => {
const { name, animal, breed, media, location, id } = props;
let hero = "http://placecorgi.com/300/300";
if (media.length) {
hero = media[0].small;
}
return (
<Link to={`/details/${id}`} className="pet">
<div className="image-container">
<img src={hero} alt={name} />
</div>
<div className="info">
<h1>{name}</h1>
<h2>{`${animal} — ${breed} — ${location}`}</h2>
</div>
</Link>
);
};
export default Pet;