Skip to content

Commit 8f114ed

Browse files
committed
Add skip & limit infinite scroll
1 parent 63ebf0a commit 8f114ed

File tree

5 files changed

+127
-52
lines changed

5 files changed

+127
-52
lines changed

src/components/Review.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,9 +245,14 @@ const withDeleteMutation = graphql(DELETE_REVIEW_MUTATION, {
245245
removeReview: true
246246
},
247247
update: store => {
248-
let data = store.readQuery({ query: REVIEWS_QUERY })
248+
const query = {
249+
query: REVIEWS_QUERY,
250+
variables: { skip: 0, limit: 10 }
251+
}
252+
253+
let data = store.readQuery(query)
249254
remove(data.reviews, { id })
250-
store.writeQuery({ query: REVIEWS_QUERY, data })
255+
store.writeQuery({ ...query, data })
251256

252257
data = store.readQuery({ query: READ_USER_FAVORITES })
253258
remove(data.currentUser.favoriteReviews, { id })

src/components/ReviewForm.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,14 @@ const withAddReview = graphql(ADD_REVIEW_MUTATION, {
155155
}
156156
},
157157
update: (store, { data: { createReview: newReview } }) => {
158-
const data = store.readQuery({
159-
query: REVIEWS_QUERY
160-
})
158+
const query = {
159+
query: REVIEWS_QUERY,
160+
variables: { skip: 0, limit: 10 }
161+
}
162+
163+
const data = store.readQuery(query)
161164
data.reviews.unshift(newReview)
162-
store.writeQuery({ query: REVIEWS_QUERY, data })
165+
store.writeQuery({ ...query, data })
163166
}
164167
})
165168
}

src/components/ReviewList.js

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import React, { Component } from 'react'
2+
import PropTypes from 'prop-types'
3+
import { graphql } from 'react-apollo'
4+
import { propType } from 'graphql-anywhere'
5+
import find from 'lodash/find'
6+
7+
import Review from './Review'
8+
9+
import { REVIEWS_QUERY, REVIEW_ENTRY } from '../graphql/Review'
10+
11+
const FETCH_MORE = 3
12+
13+
class ReviewList extends Component {
14+
componentDidMount() {
15+
window.addEventListener('scroll', this.handleScroll)
16+
}
17+
18+
componentWillUnmount() {
19+
window.removeEventListener('scroll', this.handleScroll)
20+
}
21+
22+
handleScroll = event => {
23+
if (this.props.networkStatus === FETCH_MORE) {
24+
return
25+
}
26+
27+
const currentScrollHeight = window.scrollY + window.innerHeight
28+
const pixelsFromBottom =
29+
document.documentElement.scrollHeight - currentScrollHeight
30+
if (pixelsFromBottom < 250) {
31+
this.props.loadMoreReviews()
32+
}
33+
}
34+
35+
render() {
36+
const { reviews, user } = this.props
37+
38+
return (
39+
<div className="Reviews-list">
40+
<div className="Reviews-content">
41+
{reviews &&
42+
reviews.map(review => (
43+
<Review key={review.id} review={review} user={user} />
44+
))}
45+
</div>
46+
<div className="Spinner" />
47+
</div>
48+
)
49+
}
50+
}
51+
52+
ReviewList.propTypes = {
53+
reviews: PropTypes.arrayOf(propType(REVIEW_ENTRY)),
54+
user: PropTypes.object
55+
}
56+
57+
const withReviews = graphql(REVIEWS_QUERY, {
58+
options: {
59+
errorPolicy: 'all',
60+
variables: { skip: 0, limit: 10 },
61+
notifyOnNetworkStatusChange: true
62+
},
63+
props: ({ data: { reviews, fetchMore, networkStatus } }) => ({
64+
reviews,
65+
networkStatus,
66+
loadMoreReviews: () => {
67+
return fetchMore({
68+
variables: { skip: reviews.length - 5, limit: 15 },
69+
updateQuery: (previousResult, { fetchMoreResult }) => {
70+
if (!fetchMoreResult.reviews) {
71+
return previousResult
72+
}
73+
74+
const newReviews = fetchMoreResult.reviews.filter(
75+
({ id }) => !find(previousResult.reviews, { id })
76+
)
77+
78+
return {
79+
...previousResult,
80+
reviews: [...previousResult.reviews, ...newReviews]
81+
}
82+
}
83+
})
84+
}
85+
})
86+
})
87+
88+
export default withReviews(ReviewList)

src/components/Reviews.js

Lines changed: 23 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
import React, { Component } from 'react'
22
import PropTypes from 'prop-types'
3-
import { graphql } from 'react-apollo'
43
import get from 'lodash/get'
54
import FavoriteIcon from 'material-ui-icons/Favorite'
65
import Button from 'material-ui/Button'
76
import AddIcon from 'material-ui-icons/Add'
87
import Modal from 'material-ui/Modal'
9-
import { propType } from 'graphql-anywhere'
108

11-
import Review from './Review'
9+
import ReviewList from './ReviewList'
1210
import ReviewForm from './ReviewForm'
1311

14-
import { REVIEWS_QUERY, REVIEW_ENTRY } from '../graphql/Review'
15-
1612
class Reviews extends Component {
1713
state = {
1814
addingReview: false
@@ -27,7 +23,7 @@ class Reviews extends Component {
2723
}
2824

2925
render() {
30-
const { reviews, loading, user } = this.props
26+
const { user } = this.props
3127
const favoriteCount = get(user, 'favoriteReviews.length')
3228

3329
return (
@@ -43,43 +39,34 @@ class Reviews extends Component {
4339
<h1>Reviews</h1>
4440
</header>
4541
</div>
46-
<div className="Reviews-content">
47-
{loading ? (
48-
<div className="Spinner" />
49-
) : (
50-
reviews.map(review => (
51-
<Review key={review.id} review={review} user={user} />
52-
))
53-
)}
5442

55-
{user && (
56-
<div>
57-
<Button
58-
onClick={this.addReview}
59-
variant="fab"
60-
color="primary"
61-
className="Reviews-add"
62-
>
63-
<AddIcon />
64-
</Button>
43+
<ReviewList user={user} />
6544

66-
<Modal
67-
open={this.state.addingReview}
68-
onClose={this.doneAddingReview}
69-
>
70-
<ReviewForm done={this.doneAddingReview} user={user} />
71-
</Modal>
72-
</div>
73-
)}
74-
</div>
45+
{user && (
46+
<div>
47+
<Button
48+
onClick={this.addReview}
49+
variant="fab"
50+
color="primary"
51+
className="Reviews-add"
52+
>
53+
<AddIcon />
54+
</Button>
55+
56+
<Modal
57+
open={this.state.addingReview}
58+
onClose={this.doneAddingReview}
59+
>
60+
<ReviewForm done={this.doneAddingReview} user={user} />
61+
</Modal>
62+
</div>
63+
)}
7564
</main>
7665
)
7766
}
7867
}
7968

8069
Reviews.propTypes = {
81-
reviews: PropTypes.arrayOf(propType(REVIEW_ENTRY)),
82-
loading: PropTypes.bool.isRequired,
8370
user: PropTypes.shape({
8471
favoriteReviews: PropTypes.arrayOf(
8572
PropTypes.shape({
@@ -89,12 +76,4 @@ Reviews.propTypes = {
8976
})
9077
}
9178

92-
const withReviews = graphql(REVIEWS_QUERY, {
93-
options: { errorPolicy: 'all' },
94-
props: ({ data: { reviews, loading } }) => ({
95-
reviews,
96-
loading
97-
})
98-
})
99-
100-
export default withReviews(Reviews)
79+
export default Reviews

src/graphql/Review.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ export const REVIEW_ENTRY = gql`
1717
`
1818

1919
export const REVIEWS_QUERY = gql`
20-
query ReviewsQuery {
21-
reviews(limit: 20) {
20+
query ReviewsQuery($skip: Int, $limit: Int) {
21+
reviews(skip: $skip, limit: $limit) {
2222
...ReviewEntry
2323
}
2424
}

0 commit comments

Comments
 (0)