Skip to content

Commit

Permalink
perf(card): render a card only when in viewport
Browse files Browse the repository at this point in the history
  • Loading branch information
ruddenchaux committed Apr 20, 2021
1 parent c79dde3 commit 3939961
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 57 deletions.
32 changes: 21 additions & 11 deletions src/components/characters/CharacterCard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Card, CardContent, makeStyles } from '@material-ui/core';
import React from 'react';
import useCard from '../../hooks/useCard';
import { Character } from '../../models/Character';
import CharacterCardFirstSeenIn from './CharacterCardFirstSeenIn';
import CharacterCardLastLocation from './CharacterCardLastLocation';
Expand All @@ -10,10 +11,12 @@ import CharacterCardTitle from './CharacterCardTitle';
const useStyles = makeStyles((theme) => ({
card: {
[theme.breakpoints.up('sm')]: {
display: 'flex'
display: 'flex',
height: '239px'
},
[theme.breakpoints.down('xs')]: {
display: 'block'
display: 'block',
height: '439px'
}
},
cardDetails: {
Expand All @@ -24,19 +27,26 @@ const useStyles = makeStyles((theme) => ({
export default function CharacterCard({ item, isLoading }: { item: Character; isLoading: boolean }) {
const classes = useStyles();

// hook for handle card lazy (only when the card enter in the viewport)
const [containerRef, isVisible] = useCard();

return (
<Card className={classes.card} data-cy="character-card">
<CharacterCardMedia isLoading={isLoading} character={item} />
<Card ref={containerRef as React.MutableRefObject<HTMLElement>} className={classes.card} data-cy="character-card">
{isVisible ? (
<>
<CharacterCardMedia isLoading={isLoading} character={item} />

<div className={classes.cardDetails}>
<CardContent>
<CharacterCardTitle isLoading={isLoading} character={item} />
<div className={classes.cardDetails}>
<CardContent>
<CharacterCardTitle isLoading={isLoading} character={item} />

<CharacterCardLastLocation isLoading={isLoading} character={item} />
<CharacterCardLastLocation isLoading={isLoading} character={item} />

<CharacterCardFirstSeenIn isLoading={isLoading} character={item} />
</CardContent>
</div>
<CharacterCardFirstSeenIn isLoading={isLoading} character={item} />
</CardContent>
</div>
</>
) : null}
</Card>
);
}
54 changes: 31 additions & 23 deletions src/components/episodes/EpisodeCard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Card, CardContent, Grid, makeStyles } from '@material-ui/core';
import React from 'react';
import useCard from '../../hooks/useCard';
import { Episode } from '../../models/Episode';
import CharactersAvatars from '../characters/CharactersAvatars';
import EpisodeCardAirDate from './EpisodeCardAirDate';
Expand All @@ -10,10 +11,12 @@ import EpisodeCardTitle from './EpisodeCardTitle';
const useStyles = makeStyles((theme) => ({
card: {
[theme.breakpoints.up('sm')]: {
display: 'flex'
display: 'flex',
height: '234px'
},
[theme.breakpoints.down('xs')]: {
display: 'block'
display: 'block',
height: '430.3px'
}
},
cardDetails: {
Expand All @@ -24,34 +27,39 @@ const useStyles = makeStyles((theme) => ({
export default function EpisodeCard({ item, isLoading }: { item: Episode; isLoading: boolean }) {
const classes = useStyles();

// hook for handle card lazy (only when the card enter in the viewport)
const [containerRef, isVisible] = useCard();

return (
<Card className={classes.card} data-cy="episode-card">
<CardContent className={classes.cardDetails}>
<EpisodeCardTitle isLoading={isLoading} episode={item} />
<Card ref={containerRef as React.MutableRefObject<HTMLElement>} className={classes.card} data-cy="episode-card">
{isVisible ? (
<CardContent className={classes.cardDetails}>
<EpisodeCardTitle isLoading={isLoading} episode={item} />

<Grid container>
<Grid item xs={12} sm={5} md={5} lg={5} xl={5}>
<Grid container>
<Grid item xs={6} sm={12}>
<EpisodeCardEpisode isLoading={isLoading} episode={item} />
</Grid>
<Grid container>
<Grid item xs={12} sm={5} md={5} lg={5} xl={5}>
<Grid container>
<Grid item xs={6} sm={12}>
<EpisodeCardEpisode isLoading={isLoading} episode={item} />
</Grid>

<Grid item xs={6} sm={12}>
<EpisodeCardAirDate isLoading={isLoading} episode={item} />
<Grid item xs={6} sm={12}>
<EpisodeCardAirDate isLoading={isLoading} episode={item} />
</Grid>
</Grid>
</Grid>
</Grid>

<Grid item xs={12} sm={7} md={7} lg={7} xl={7}>
<CharactersAvatars
label="Characters"
characters={item?.characters}
dialogTitle={`Characters in ${item?.name} episode`}
isLoading={isLoading}
/>
<Grid item xs={12} sm={7} md={7} lg={7} xl={7}>
<CharactersAvatars
label="Characters"
characters={item?.characters}
dialogTitle={`Characters in ${item?.name} episode`}
isLoading={isLoading}
/>
</Grid>
</Grid>
</Grid>
</CardContent>
</CardContent>
) : null}
</Card>
);
}
54 changes: 31 additions & 23 deletions src/components/locations/LocationCard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Card, CardContent, Grid, makeStyles } from '@material-ui/core';
import React from 'react';
import useCard from '../../hooks/useCard';
import { Location } from '../../models/Location';
import CharactersAvatars from '../characters/CharactersAvatars';
import LocationCardDimension from './LocationCardDimension';
Expand All @@ -10,10 +11,12 @@ import LocationCardType from './LocationCardType';
const useStyles = makeStyles((theme) => ({
card: {
[theme.breakpoints.up('sm')]: {
display: 'flex'
display: 'flex',
height: '234px'
},
[theme.breakpoints.down('xs')]: {
display: 'block'
display: 'block',
height: '430.3px'
}
},
cardDetails: {
Expand All @@ -24,34 +27,39 @@ const useStyles = makeStyles((theme) => ({
export default function LocationCard({ item, isLoading }: { item: Location; isLoading: boolean }) {
const classes = useStyles();

// hook for handle card lazy (only when the card enter in the viewport)
const [containerRef, isVisible] = useCard();

return (
<Card className={classes.card} data-cy="location-card">
<CardContent className={classes.cardDetails}>
<LocationCardTitle isLoading={isLoading} location={item} />
<Card ref={containerRef as React.MutableRefObject<HTMLElement>} className={classes.card} data-cy="location-card">
{isVisible ? (
<CardContent className={classes.cardDetails}>
<LocationCardTitle isLoading={isLoading} location={item} />

<Grid container>
<Grid item xs={12} sm={5} md={5} lg={5} xl={5}>
<Grid container>
<Grid item xs={6} sm={12}>
<LocationCardType isLoading={isLoading} location={item} />
</Grid>
<Grid container>
<Grid item xs={12} sm={5} md={5} lg={5} xl={5}>
<Grid container>
<Grid item xs={6} sm={12}>
<LocationCardType isLoading={isLoading} location={item} />
</Grid>

<Grid item xs={6} sm={12}>
<LocationCardDimension isLoading={isLoading} location={item} />
<Grid item xs={6} sm={12}>
<LocationCardDimension isLoading={isLoading} location={item} />
</Grid>
</Grid>
</Grid>
</Grid>

<Grid item xs={12} sm={7} md={7} lg={7} xl={7}>
<CharactersAvatars
label="Characters"
characters={item?.residents}
dialogTitle={`Residents of ${item?.name} location`}
isLoading={isLoading}
/>
<Grid item xs={12} sm={7} md={7} lg={7} xl={7}>
<CharactersAvatars
label="Characters"
characters={item?.residents}
dialogTitle={`Residents of ${item?.name} location`}
isLoading={isLoading}
/>
</Grid>
</Grid>
</Grid>
</CardContent>
</CardContent>
) : null}
</Card>
);
}
12 changes: 12 additions & 0 deletions src/hooks/useCard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import useIntersectionObserver from './useIntersectionObserver';

/**
* hook for handle card lazy (only when the card enter in the viewport)
*/
export default () =>
useIntersectionObserver({
root: null,
rootMargin: '0px',
threshold: 0
});

0 comments on commit 3939961

Please sign in to comment.