Speed up and clarify the 'load more comments' UI

* only rerender the comments after loading and iff something changes
 * change text to 'loading...' and make link unclickable while waiting
 * if all comments are already loaded, rename to 'load new comments'
This commit is contained in:
Christopher Gurnee 2022-02-21 17:41:03 -05:00
parent 59df221ff9
commit aac22ce109
6 changed files with 70 additions and 26 deletions

2
dist/main.css vendored

File diff suppressed because one or more lines are too long

View file

@ -93,10 +93,11 @@ export const getComments = async (allComments, threadID, maxComments, after) =>
parent_id: c.parent_id?.substring(3) || threadID,
link_id: c.link_id?.substring(3) || threadID
}))
if (comments.length < chunkSize/2 || chunks <= 1)
break
if (comments.length < chunkSize/2)
return [ comments[comments.length - 1].created_utc, true ]
if (chunks <= 1)
return [ comments[comments.length - 1].created_utc, false ]
chunks--
after = Math.max(comments[comments.length - 1].created_utc - 1, after + 1)
}
return comments[comments.length - 1].created_utc
}

View file

@ -1,6 +1,6 @@
import React from 'react'
import Comment from './Comment'
import {connect, sort, filter, maxCommentsDefault} from '../../state'
import {sort, filter} from '../../state'
import {
topSort, bottomSort, newSort, oldSort,
showRemovedAndDeleted, showRemoved, showDeleted
@ -71,8 +71,7 @@ const filterCommentTree = (comments, filterFunction) => {
const commentSection = (props) => {
console.time('render comment section')
const commentTree = unflatten(props.comments, props.root, props.removed, props.deleted)
const {commentFilter, commentSort} = props.global.state
const maxCommentsPreferred = props.global.getMaxComments()
const {commentFilter, commentSort} = props
if (commentFilter === filter.removedDeleted) {
filterCommentTree(commentTree, showRemovedAndDeleted)
@ -95,26 +94,29 @@ const commentSection = (props) => {
return (
commentTree.length !== 0
? <> {commentTree.map(comment => (
? commentTree.map(comment => (
<Comment
key={comment.id}
{...comment}
depth={0}
postAuthor={props.postAuthor}
/>
))}
<p className='load-more'>
{maxCommentsPreferred <= maxCommentsDefault / 2 &&
<a onClick={() => props.global.loadMoreComments(maxCommentsPreferred)}>load {maxCommentsPreferred} more comments</a>
}
<a onClick={() => props.global.loadMoreComments(maxCommentsDefault)}>load {maxCommentsDefault} more comments</a>
{maxCommentsPreferred >= maxCommentsDefault * 2 &&
<a onClick={() => props.global.loadMoreComments(maxCommentsPreferred)}>load {maxCommentsPreferred} more comments</a>
}
</p>
</>
))
: <p>No comments found</p>
)
}
export default connect(commentSection)
const areEqual = (prevProps, nextProps) => {
if (prevProps.commentFilter !== nextProps.commentFilter ||
prevProps.commentSort !== nextProps.commentSort ||
prevProps.root !== nextProps.root)
return false
if (nextProps.reloadingComments)
return true
return prevProps.total === nextProps.total &&
prevProps.removed.length === nextProps.removed.length &&
prevProps.deleted.length === nextProps.deleted.length &&
prevProps.postAuthor === nextProps.postAuthor
}
export default React.memo(commentSection, areEqual)

View file

@ -0,0 +1,25 @@
import React from 'react'
import {connect, maxCommentsDefault} from '../../state'
const loadMore = (props) => {
const maxCommentsPreferred = props.global.getMaxComments()
if (props.reloadingComments)
return <p className='loading-more'><span>loading...</span></p>
else if (props.loadedAllComments)
return <p className='load-more'>
<a onClick={() => props.global.loadMoreComments(maxCommentsDefault)}>load new comments</a>
</p>
else
return <p className='load-more'>
{maxCommentsPreferred <= maxCommentsDefault / 2 &&
<a onClick={() => props.global.loadMoreComments(maxCommentsPreferred)}>load {maxCommentsPreferred} more comments</a>
}
<a onClick={() => props.global.loadMoreComments(maxCommentsDefault)}>load {maxCommentsDefault} more comments</a>
{maxCommentsPreferred >= maxCommentsDefault * 2 &&
<a onClick={() => props.global.loadMoreComments(maxCommentsPreferred)}>load {maxCommentsPreferred} more comments</a>
}
</p>
}
export default connect(loadMore)

View file

@ -14,6 +14,7 @@ import Post from '../common/Post'
import CommentSection from './CommentSection'
import SortBy from './SortBy'
import CommentInfo from './CommentInfo'
import LoadMore from './LoadMore'
class Thread extends React.Component {
state = {
@ -21,6 +22,7 @@ class Thread extends React.Component {
pushshiftCommentLookup: new Map(),
removed: [],
deleted: [],
loadedAllComments: false,
loadingComments: true,
reloadingComments: false
}
@ -87,7 +89,7 @@ class Thread extends React.Component {
// Get comment ids from pushshift
getPushshiftComments(pushshiftCommentLookup, threadID, newCommentCount, after)
.then(lastCreatedUtc => {
.then(([lastCreatedUtc, loadedAllComments]) => {
console.log(`Pushshift: ${pushshiftCommentLookup.size} comments`)
const ids = []
const missingIds = new Set()
@ -151,6 +153,7 @@ class Thread extends React.Component {
pushshiftCommentLookup,
removed,
deleted,
loadedAllComments,
loadingComments: false,
reloadingComments: false
})
@ -186,11 +189,11 @@ class Thread extends React.Component {
const root = isSingleComment ? commentID : id
return (
<React.Fragment>
<>
<Post {...this.state.post} />
{
(!this.state.loadingComments && root) &&
<React.Fragment>
<>
<CommentInfo
total={this.state.pushshiftCommentLookup.size}
removed={this.state.removed.length}
@ -211,10 +214,18 @@ class Thread extends React.Component {
removed={this.state.removed}
deleted={this.state.deleted}
postAuthor={isDeleted(author) ? null : author}
commentFilter={this.props.global.state.commentFilter} // need to explicitly
commentSort={this.props.global.state.commentSort} // pass in these props
reloadingComments={this.state.reloadingComments} // to ensure React.memo
total={this.state.pushshiftCommentLookup.size} // works correctly
/>
</React.Fragment>
<LoadMore
loadedAllComments={this.state.loadedAllComments}
reloadingComments={this.state.reloadingComments}
/>
</>
}
</React.Fragment>
</>
)
}
}

View file

@ -143,8 +143,13 @@
.load-more a
color: $author
font-weight: bold
font-size: 10px
margin-left: 16px
cursor: pointer
.loading-more span
color: $link
font-weight: bold
font-size: 10px
margin-left: 16px