diff --git a/src/api/pushshift/index.js b/src/api/pushshift/index.js index 6f66ac5..6e26719 100644 --- a/src/api/pushshift/index.js +++ b/src/api/pushshift/index.js @@ -75,7 +75,7 @@ export const getPost = async threadID => { // retrieved. It should return as quickly as possible (scheduling time-taking work // later), and may return false to cause getComments to exit early, or true otherwise. export const getComments = async (callback, threadID, maxComments, after) => { - let chunks = Math.ceil(maxComments / chunkSize), comments, lastCreatedUtc = 1 + let chunks = Math.floor(maxComments / chunkSize), comments, lastCreatedUtc = 1 while (true) { let delay = 0 diff --git a/src/pages/thread/LoadMore.js b/src/pages/thread/LoadMore.js index fe00679..e9ffda0 100644 --- a/src/pages/thread/LoadMore.js +++ b/src/pages/thread/LoadMore.js @@ -1,14 +1,14 @@ import React from 'react' -import {connect, getMaxComments, maxCommentsDefault} from '../../state' +import {connect, maxCommentsDefault} from '../../state' -let lastTotal +let loadingStarted = false, showLoadedCount = false, lastTotal, newComments const loadMoreComments = (props, maxComments) => { - lastTotal = props.total + loadingStarted = true props.global.loadMoreComments(maxComments) } const loadMore = (props) => { - const maxCommentsPreferred = getMaxComments() + const maxCommentsPreferred = props.global.maxComments let loadElements if (props.reloadingComments) @@ -24,8 +24,16 @@ const loadMore = (props) => { if (maxCommentsPreferred >= maxCommentsDefault * 2) loadElements.push( loadMoreComments(props, maxCommentsPreferred)}>load {maxCommentsPreferred} more comments) } - if (lastTotal !== undefined) { - const newComments = props.total - lastTotal + if (loadingStarted) { + showLoadedCount = true + newComments = props.total - lastTotal + lastTotal = props.total + loadingStarted = false + } else if (lastTotal !== props.total) { + showLoadedCount = false + lastTotal = props.total + } + if (showLoadedCount) { loadElements.push( {newComments > 0 ? `loaded ${newComments} more comments` : 'no new comments found'} ) diff --git a/src/pages/thread/SortBy.js b/src/pages/thread/SortBy.js index dbbc106..9c70486 100644 --- a/src/pages/thread/SortBy.js +++ b/src/pages/thread/SortBy.js @@ -1,9 +1,9 @@ import React, { useState } from 'react' -import {connect, sort, filter, getMaxComments, saveMaxComments, minCommentsLimit, maxCommentsLimit} from '../../state' +import {connect, sort, filter, minCommentsLimit, maxCommentsLimit, constrainMaxComments} from '../../state' const sortBy = props => { - const [maxCommentsField, setMaxCommentsField] = useState(props.global.state.maxComments) - const initSavedMaxComments = getMaxComments() + // The current value of the field; it'll be later saved after an onBlur event + const [maxCommentsField, setMaxCommentsField] = useState(props.global.maxComments) const isFirefox = typeof InstallTrigger !== 'undefined' let usedMouse; @@ -41,16 +41,16 @@ const sortBy = props => { e.key == "Enter" && e.target.blur()} onChange= {e => setMaxCommentsField(parseInt(e.target.value))} - onBlur= {e => e.target.value = saveMaxComments(e.target.value)} + onBlur= {e => e.target.value = props.global.setMaxComments(e.target.value)} { ...(isFirefox ? { onClick: e => e.target.focus() } : {}) } - defaultValue={initSavedMaxComments} type='number' maxLength='5' required + defaultValue={props.global.maxComments} type='number' maxLength='5' required min={minCommentsLimit} max={maxCommentsLimit} step={minCommentsLimit} /> - { maxCommentsField > props.global.state.maxComments && props.global.state.maxComments < maxCommentsLimit && !props.reloadingComments && + { !props.loadedAllComments && !props.reloadingComments && constrainMaxComments(maxCommentsField) - minCommentsLimit >= props.total && - {props.global.loadMaxComments()}} type='button' value='Reload' /> + props.global.loadMoreComments(props.global.maxComments - props.total)} type='button' value='Reload' /> } ) diff --git a/src/pages/thread/index.js b/src/pages/thread/index.js index 9e7f12b..c1a2cd2 100644 --- a/src/pages/thread/index.js +++ b/src/pages/thread/index.js @@ -59,12 +59,6 @@ class Thread extends React.Component { componentDidMount () { const { subreddit, threadID } = this.props.match.params - let maxCommentsQuery = parseInt((new URLSearchParams(this.props.location.search)).get('max_comments')) - if (maxCommentsQuery > this.props.global.state.maxComments) - // Directly mutating the state is not recommended, but it's only done once and is probably OK here - this.props.global.state.maxComments = this.curMaxComments = constrainMaxComments(maxCommentsQuery) - else - this.curMaxComments = this.props.global.state.maxComments this.props.global.setLoading('Loading post...') // Get post from reddit @@ -111,16 +105,18 @@ class Thread extends React.Component { this.props.global.setLoading('Loading comments from Pushshift...') }) - this.getComments(this.props.global.state.maxComments, 0) + const maxCommentsQuery = constrainMaxComments( + parseInt((new URLSearchParams(this.props.location.search)).get('max_comments'))) + this.getComments(Math.max(this.props.global.maxComments, maxCommentsQuery), 0) } componentDidUpdate () { - const newCommentCount = this.props.global.state.maxComments - this.curMaxComments - if (newCommentCount > 0) { - this.curMaxComments = this.props.global.state.maxComments + const { loadingMoreComments } = this.props.global.state + if (loadingMoreComments) { + this.props.global.state.loadingMoreComments = 0 this.setState({reloadingComments: true}) this.props.global.setLoading('Loading more comments from Pushshift...') - this.getComments(newCommentCount, this.lastCreatedUtc - 1) + this.getComments(loadingMoreComments, this.lastCreatedUtc - 1) } } @@ -234,6 +230,7 @@ class Thread extends React.Component { render () { const { subreddit, id, author } = this.state.post const { commentID } = this.props.match.params + const reloadingComments = this.state.reloadingComments || this.props.global.state.loadingMoreComments const linkToRestOfComments = `/r/${subreddit}/comments/${id}/_/` const isSingleComment = commentID !== undefined @@ -251,7 +248,9 @@ class Thread extends React.Component { deleted={this.state.deleted.length} /> {isSingleComment &&
@@ -267,12 +266,12 @@ class Thread extends React.Component { 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 + reloadingComments={reloadingComments} // to ensure React.memo total={this.state.pushshiftCommentLookup.size} // works correctly /> diff --git a/src/state.js b/src/state.js index afa4e5e..0f87031 100644 --- a/src/state.js +++ b/src/state.js @@ -31,16 +31,6 @@ export const constrainMaxComments = maxComments => { return maxComments } -// Contrains, saves, and returns it, but does not change the state (does not load more comments) -export const saveMaxComments = maxComments => { - maxComments = constrainMaxComments(maxComments) - put(maxCommentsKey, maxComments) - return maxComments -} - -// Gets the saved setting, regardless of the current state -export const getMaxComments = () => get(maxCommentsKey, maxCommentsDefault) - // Keys for localStorage const sortKey = 'commentSort' const filterKey = 'commentFilter' @@ -50,12 +40,15 @@ class GlobalState extends Container { state = { commentSort: get(sortKey, sort.top), commentFilter: get(filterKey, filter.removedDeleted), - maxComments: get(maxCommentsKey, maxCommentsDefault), + loadingMoreComments: 0, // max # of comments to attempt to load next statusText: '', statusHelpUrl: undefined, statusImage: undefined } + // Preferred max # of comments to get during (re-)loads + maxComments = get(maxCommentsKey, maxCommentsDefault) + setCommentSort (sortType) { put(sortKey, sortType) this.setState({commentSort: sortType}) @@ -66,11 +59,15 @@ class GlobalState extends Container { this.setState({commentFilter: filterType}) } - // Sets the current state based on the saved setting (loads more comments) - loadMaxComments = () => this.setState({maxComments: getMaxComments()}) + // Contrains, saves, and returns it (does not load more comments) + setMaxComments (maxComments) { + this.maxComments = constrainMaxComments(maxComments) + put(maxCommentsKey, this.maxComments) + return this.maxComments + } - // Sets the current state loading moreComments, ignoring the saved setting - loadMoreComments = moreComments => this.setState({maxComments: this.state.maxComments + moreComments}) + // Loads more comments + loadMoreComments = loadingMoreComments => this.setState({loadingMoreComments}) setSuccess = () => { this.setState({statusText: '', statusHelpUrl: undefined, statusImage: '/images/success.png'})