diff --git a/webclient/src/Comments.js b/webclient/src/Comments.js index 91a517f..0da6c6b 100644 --- a/webclient/src/Comments.js +++ b/webclient/src/Comments.js @@ -1,35 +1,32 @@ -import React from 'react'; -import { Link } from 'react-router-dom'; +import React, { useState, useEffect, useCallback } from 'react'; +import { Link, useParams } from 'react-router-dom'; import { HashLink } from 'react-router-hash-link'; import { Helmet } from 'react-helmet'; import moment from 'moment'; import localForage from 'localforage'; import { infoLine, ToggleDot } from './utils.js'; -class Comments extends React.Component { - constructor(props) { - super(props); +function countComments(c) { + return c.comments.reduce((sum, x) => sum + countComments(x), 1); +} - const id = this.props.match.params.id; - const cache = this.props.cache; +function Comments({ cache }) { + const { id } = useParams(); - if (id in cache) console.log('cache hit'); + if (id in cache) console.log('cache hit'); - this.state = { - story: cache[id] || false, - error: false, - collapsed: [], - expanded: [], - }; - } - - componentDidMount() { - const id = this.props.match.params.id; + const [story, setStory] = useState(cache[id] || false); + const [error, setError] = useState(false); + const [collapsed, setCollapsed] = useState([]); + const [expanded, setExpanded] = useState([]); + useEffect(() => { localForage.getItem(id) .then( (value) => { - this.setState({ story: value }); + if (value) { + setStory(value); + } } ); @@ -37,47 +34,41 @@ class Comments extends React.Component { .then(res => res.json()) .then( (result) => { - this.setState({ story: result.story }, () => { - const hash = window.location.hash.substring(1); - if (hash) { - document.getElementById(hash).scrollIntoView(); - } - }); + setStory(result.story); localForage.setItem(id, result.story); + const hash = window.location.hash.substring(1); + if (hash) { + setTimeout(() => { + const element = document.getElementById(hash); + if (element) { + element.scrollIntoView(); + } + }, 0); + } }, (error) => { - this.setState({ error: true }); + setError(true); } ); - } + }, [id]); - collapseComment(cid) { - this.setState(prevState => ({ - ...prevState, - collapsed: [...prevState.collapsed, cid], - expanded: prevState.expanded.filter(x => x !== cid), - })); - } + const collapseComment = useCallback((cid) => { + setCollapsed(prev => [...prev, cid]); + setExpanded(prev => prev.filter(x => x !== cid)); + }, []); - expandComment(cid) { - this.setState(prevState => ({ - ...prevState, - collapsed: prevState.collapsed.filter(x => x !== cid), - expanded: [...prevState.expanded, cid], - })); - } + const expandComment = useCallback((cid) => { + setCollapsed(prev => prev.filter(x => x !== cid)); + setExpanded(prev => [...prev, cid]); + }, []); - countComments(c) { - return c.comments.reduce((sum, x) => sum + this.countComments(x), 1); - } - - displayComment(story, c, level) { + const displayComment = useCallback((story, c, level) => { const cid = c.author+c.date; - const collapsed = this.state.collapsed.includes(cid); - const expanded = this.state.expanded.includes(cid); + const isCollapsed = collapsed.includes(cid); + const isExpanded = expanded.includes(cid); - const hidden = collapsed || (level == 4 && !expanded); + const hidden = isCollapsed || (level == 4 && !isExpanded); const hasChildren = c.comments.length !== 0; return ( @@ -88,56 +79,50 @@ class Comments extends React.Component { {' '} | {moment.unix(c.date).fromNow()} {hidden || hasChildren && - this.collapseComment(cid)}>– + collapseComment(cid)}>– }

-
+
{hidden && hasChildren ? -
this.expandComment(cid)}>[show {this.countComments(c)-1} more]
+
expandComment(cid)}>[show {countComments(c)-1} more]
: - c.comments.map(i => this.displayComment(story, i, level + 1)) + c.comments.map(i => displayComment(story, i, level + 1)) }
); - } + }, [collapsed, expanded, collapseComment, expandComment]); - render() { - const id = this.props.match.params.id; - const story = this.state.story; - const error = this.state.error; + return ( +
+ {error &&

Connection error?

} + {story ? +
+ + {story.title} | QotNews + + - return ( -
- {error &&

Connection error?

} - {story ? -
- - {story.title} | QotNews - - +

{story.title}

-

{story.title}

- -
- View article -
- - {infoLine(story)} - -
- {story.comments.map(c => this.displayComment(story, c, 0))} -
+
+ View article
- : -

loading...

- } - -
- ); - } + + {infoLine(story)} + +
+ {story.comments.map(c => displayComment(story, c, 0))} +
+
+ : +

loading...

+ } + +
+ ); } export default Comments;