From 0081278e3c89422b9898f4a534f59ecbf4e00ecf Mon Sep 17 00:00:00 2001 From: Christopher Gurnee Date: Wed, 9 Mar 2022 16:15:41 +0000 Subject: [PATCH] Replace maxComments in state w/loadingMoreComments maxComments is now only the user-preferred setting, and has nothing to do with displayed state. loadingMoreComments is used to trigger loading more comments, and temporarily contains the desired comment count to load. This should make future changes easier. Also fix two minor bugs: * the 'Reload' was sometimes hidden after clicking 'load more comments' * 'loaded x more comments' incorrectly appeared after clicking 'Reload' --- src/api/pushshift/index.js | 2 +- src/pages/thread/LoadMore.js | 20 ++++++++++++++------ src/pages/thread/SortBy.js | 14 +++++++------- src/pages/thread/index.js | 27 +++++++++++++-------------- src/state.js | 27 ++++++++++++--------------- 5 files changed, 47 insertions(+), 43 deletions(-) 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'})