From 0595050538feed1bde70db12486db92407ebafde Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Sat, 15 Feb 2020 00:51:22 +0900 Subject: [PATCH 1/7] Move API calls on community page to client side --- pages/community.js | 22 ++------------ src/components/Community/Learn/index.js | 26 +++++++++++------ src/components/Community/Meet/index.js | 38 +++++++++++++++++++------ src/components/Community/index.js | 13 ++------- src/utils/api.js | 26 ++++++++++++----- 5 files changed, 72 insertions(+), 53 deletions(-) diff --git a/pages/community.js b/pages/community.js index c4a2a88d98..2553720e5a 100644 --- a/pages/community.js +++ b/pages/community.js @@ -1,17 +1,11 @@ import React from 'react' import Head from 'next/head' -import { - getLatestIssues, - getLatestTopics, - getLatestPosts -} from '../src/utils/api' - import Community from '../src/components/Community' import { META_BASE_TITLE } from '../src/consts' -export default function CommunityPage(props) { +export default function CommunityPage() { return ( <> @@ -28,19 +22,7 @@ export default function CommunityPage(props) { /> Community | {META_BASE_TITLE} - + ) } - -CommunityPage.getInitialProps = async ({ req }) => { - const issues = await getLatestIssues(req) - const posts = await getLatestPosts(req) - const topics = await getLatestTopics(req) - - return { - issues, - posts, - topics - } -} diff --git a/src/components/Community/Learn/index.js b/src/components/Community/Learn/index.js index 0b34b74060..1e42693d6a 100644 --- a/src/components/Community/Learn/index.js +++ b/src/components/Community/Learn/index.js @@ -10,6 +10,7 @@ import CommunityBlock from '../Block' import CommunityButton from '../Button' import CommunitySection from '../Section' +import { getLatestPosts, getCommentsCount } from '../../../utils/api' import { pluralizeComments } from '../../../utils/i18n' import { @@ -53,9 +54,7 @@ function CommunityBlogPost({ useEffect(() => { if (commentsUrl) { - fetch(`/api/comments?url=${commentsUrl}`) - .then(result => result.json()) - .then(data => setCount(data.count)) + getCommentsCount(commentsUrl).then(result => setCount(result)) } }, []) @@ -185,7 +184,17 @@ CommunityDocumentation.propTypes = { url: PropTypes.string } -export default function CommunityLearn({ posts, theme }) { +export default function CommunityLearn({ theme }) { + const [isPostsLoaded, setIsPostsLoaded] = useState(false) + const [posts, setPosts] = useState([]) + + useEffect(() => { + getLatestPosts().then(result => { + setPosts(result) + setIsPostsLoaded(true) + }) + }, []) + return ( - {posts.length ? ( + {!isPostsLoaded && Loading...} + {isPostsLoaded && + !!posts.length && posts.map(post => ( - )) - ) : ( + ))} + {isPostsLoaded && !posts.length && ( Blog is unavailable right now )} @@ -286,7 +297,6 @@ export default function CommunityLearn({ posts, theme }) { } CommunityLearn.propTypes = { - posts: PropTypes.array, theme: PropTypes.shape({ backgroundColor: PropTypes.string, color: PropTypes.string diff --git a/src/components/Community/Meet/index.js b/src/components/Community/Meet/index.js index bcddb9c897..a81241f5d4 100644 --- a/src/components/Community/Meet/index.js +++ b/src/components/Community/Meet/index.js @@ -1,4 +1,4 @@ -import React, { useCallback } from 'react' +import React, { useCallback, useEffect, useState } from 'react' import PropTypes from 'prop-types' import formatDistanceToNow from 'date-fns/formatDistanceToNow' @@ -8,6 +8,7 @@ import CommunitySection from '../Section' import { pluralizeComments } from '../../../utils/i18n' import { logEvent } from '../../../utils/ga' +import { getLatestIssues, getLatestTopics } from '../../../utils/api' import data from '../data' @@ -110,7 +111,24 @@ CommunityIssue.propTypes = { color: PropTypes.string } -export default function CommunityMeet({ issues, theme, topics }) { +export default function CommunityMeet({ theme }) { + const [isIssuesLoaded, setIsIssuesLoaded] = useState(false) + const [issues, setIssues] = useState([]) + + const [isTopicsLoaded, setIsTopicsLoaded] = useState(false) + const [topics, setTopics] = useState([]) + + useEffect(() => { + getLatestIssues().then(result => { + setIssues(result) + setIsIssuesLoaded(true) + }) + getLatestTopics().then(result => { + setTopics(result) + setIsTopicsLoaded(true) + }) + }, []) + return ( - {topics.length ? ( + {!isTopicsLoaded && Loading...} + {isTopicsLoaded && + !!topics.length && topics.map(topic => ( - )) - ) : ( + ))} + {isTopicsLoaded && !topics.length && ( Forum is unavailable right now )} @@ -231,15 +251,17 @@ export default function CommunityMeet({ issues, theme, topics }) { } icon="/static/img/community/github.svg" > - {issues.length ? ( + {!isIssuesLoaded && Loading...} + {isIssuesLoaded && + !!issues.length && issues.map(issue => ( - )) - ) : ( + ))} + {isIssuesLoaded && !issues.lengts && ( Github is unavailable right now )} diff --git a/src/components/Community/index.js b/src/components/Community/index.js index b73c2be15a..07b2b61fdb 100644 --- a/src/components/Community/index.js +++ b/src/components/Community/index.js @@ -1,5 +1,4 @@ import React from 'react' -import PropTypes from 'prop-types' import Page from '../Page' import Subscribe from '../Subscribe' @@ -18,23 +17,17 @@ const themes = { purple: { backgroundColor: '#DCD6F1', color: '#955DD6' } } -export default function Community({ issues, posts, topics }) { +export default function Community() { return ( - + - + ) } - -Community.propTypes = { - issues: PropTypes.array, - posts: PropTypes.array, - topics: PropTypes.array -} diff --git a/src/utils/api.js b/src/utils/api.js index 773209d351..6a14e90205 100644 --- a/src/utils/api.js +++ b/src/utils/api.js @@ -6,10 +6,9 @@ export function makeAbsoluteURL(req, uri) { return `${protocol}//${host}${uri}` } - -export async function getLatestIssues(req) { +export async function getLatestIssues() { try { - const res = await fetch(makeAbsoluteURL(req, '/api/github')) + const res = await fetch('/api/github') if (res.status !== 200) return [] @@ -23,9 +22,9 @@ export async function getLatestIssues(req) { } } -export async function getLatestPosts(req) { +export async function getLatestPosts() { try { - const res = await fetch(makeAbsoluteURL(req, '/api/blog')) + const res = await fetch('/api/blog') if (res.status !== 200) return [] @@ -39,9 +38,9 @@ export async function getLatestPosts(req) { } } -export async function getLatestTopics(req) { +export async function getLatestTopics() { try { - const res = await fetch(makeAbsoluteURL(req, '/api/discourse')) + const res = await fetch('/api/discourse') if (res.status !== 200) return [] @@ -54,3 +53,16 @@ export async function getLatestTopics(req) { return [] } } + +export async function getCommentsCount(commentsUrl) { + try { + const res = await fetch(`/api/comments?url=${commentsUrl}`) + + if (res.status === 200) { + const { count } = await res.json() + return count + } + } catch (e) { + console.error(e) + } +} From fbcc361f3797a2d774795ae4a766b25919ed7c65 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Sat, 15 Feb 2020 02:41:52 +0900 Subject: [PATCH 2/7] Replace API functions with hooks --- src/components/Community/Learn/index.js | 40 ++++------- src/components/Community/Meet/index.js | 52 +++++--------- src/utils/api.js | 91 +++++++++++++------------ 3 files changed, 76 insertions(+), 107 deletions(-) diff --git a/src/components/Community/Learn/index.js b/src/components/Community/Learn/index.js index 1e42693d6a..5783e71178 100644 --- a/src/components/Community/Learn/index.js +++ b/src/components/Community/Learn/index.js @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useState } from 'react' +import React, { useCallback } from 'react' import PropTypes from 'prop-types' import format from 'date-fns/format' @@ -10,7 +10,7 @@ import CommunityBlock from '../Block' import CommunityButton from '../Button' import CommunitySection from '../Section' -import { getLatestPosts, getCommentsCount } from '../../../utils/api' +import { usePosts, useCommentsCount } from '../../../utils/api' import { pluralizeComments } from '../../../utils/i18n' import { @@ -46,17 +46,10 @@ function CommunityBlogPost({ commentsUrl, pictureUrl }) { - const [count, setCount] = useState() - const loaded = count !== undefined const logPost = useCallback(() => logEvent('community', 'blog', title), [ title ]) - - useEffect(() => { - if (commentsUrl) { - getCommentsCount(commentsUrl).then(result => setCount(result)) - } - }, []) + const { error, ready, result } = useCommentsCount(commentsUrl) return ( @@ -81,14 +74,14 @@ function CommunityBlogPost({ {title} - {loaded && ( + {ready && !error && ( <> - {pluralizeComments(count)} + {pluralizeComments(result)} {' • '} @@ -185,15 +178,7 @@ CommunityDocumentation.propTypes = { } export default function CommunityLearn({ theme }) { - const [isPostsLoaded, setIsPostsLoaded] = useState(false) - const [posts, setPosts] = useState([]) - - useEffect(() => { - getLatestPosts().then(result => { - setPosts(result) - setIsPostsLoaded(true) - }) - }, []) + const { error, ready, result: posts } = usePosts() return ( @@ -251,7 +236,7 @@ export default function CommunityLearn({ theme }) { } action={ - posts.length && ( + posts && ( - {!isPostsLoaded && Loading...} - {isPostsLoaded && - !!posts.length && + {!ready && Loading...} + {error && ( + Blog is unavailable right now + )} + {posts && posts.map(post => ( ))} - {isPostsLoaded && !posts.length && ( - Blog is unavailable right now - )} diff --git a/src/components/Community/Meet/index.js b/src/components/Community/Meet/index.js index a81241f5d4..aea0737410 100644 --- a/src/components/Community/Meet/index.js +++ b/src/components/Community/Meet/index.js @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useState } from 'react' +import React, { useCallback } from 'react' import PropTypes from 'prop-types' import formatDistanceToNow from 'date-fns/formatDistanceToNow' @@ -8,7 +8,7 @@ import CommunitySection from '../Section' import { pluralizeComments } from '../../../utils/i18n' import { logEvent } from '../../../utils/ga' -import { getLatestIssues, getLatestTopics } from '../../../utils/api' +import { useIssues, useTopics } from '../../../utils/api' import data from '../data' @@ -112,22 +112,8 @@ CommunityIssue.propTypes = { } export default function CommunityMeet({ theme }) { - const [isIssuesLoaded, setIsIssuesLoaded] = useState(false) - const [issues, setIssues] = useState([]) - - const [isTopicsLoaded, setIsTopicsLoaded] = useState(false) - const [topics, setTopics] = useState([]) - - useEffect(() => { - getLatestIssues().then(result => { - setIssues(result) - setIsIssuesLoaded(true) - }) - getLatestTopics().then(result => { - setTopics(result) - setIsTopicsLoaded(true) - }) - }, []) + const { erorr: issuesError, ready: issuesReady, result: issues } = useIssues() + const { erorr: topicsError, ready: topicsReady, result: topics } = useTopics() return ( @@ -195,7 +181,7 @@ export default function CommunityMeet({ theme }) { } action={ - topics.length && ( + topics && ( - {!isTopicsLoaded && Loading...} - {isTopicsLoaded && - !!topics.length && + {!topicsReady && Loading...} + {topicsError && ( + Forum is unavailable right now + )} + {topics && topics.map(topic => ( ))} - {isTopicsLoaded && !topics.length && ( - Forum is unavailable right now - )} @@ -237,7 +222,7 @@ export default function CommunityMeet({ theme }) { } action={ - issues.length && ( + issues && ( - {!isIssuesLoaded && Loading...} - {isIssuesLoaded && - !!issues.length && + {!issuesReady && Loading...} + {issuesError && ( + Github is unavailable right now + )} + {issues && issues.map(issue => ( ))} - {isIssuesLoaded && !issues.lengts && ( - Github is unavailable right now - )} @@ -273,10 +257,8 @@ export default function CommunityMeet({ theme }) { } CommunityMeet.propTypes = { - issues: PropTypes.array, theme: PropTypes.shape({ backgroundColor: PropTypes.string, color: PropTypes.string - }), - topics: PropTypes.array + }) } diff --git a/src/utils/api.js b/src/utils/api.js index 6a14e90205..7c096b950e 100644 --- a/src/utils/api.js +++ b/src/utils/api.js @@ -1,3 +1,4 @@ +import { useEffect, useState } from 'react' import fetch from 'isomorphic-fetch' export function makeAbsoluteURL(req, uri) { @@ -6,63 +7,65 @@ export function makeAbsoluteURL(req, uri) { return `${protocol}//${host}${uri}` } -export async function getLatestIssues() { - try { - const res = await fetch('/api/github') - if (res.status !== 200) return [] +const useAPICall = url => { + const [ready, setReady] = useState(false) + const [error, setError] = useState(false) + const [result, setResult] = useState(null) + + useEffect(() => { + let cancelled = false + + const fetchData = async () => { + try { + const res = await fetch(url) + + if (!cancelled) { + if (res.status !== 200) { + setError('Wrong response types') + } else { + setResult(await res.json()) + } + } + } catch { + if (!cancelled) setError('Error loading request') + } finally { + if (!cancelled) setReady(true) + } + } - const { issues } = await res.json() + fetchData() - return issues - } catch (e) { - console.error(e) + return () => { + cancelled = true + } + }, []) - return [] - } + return { error, ready, result } } -export async function getLatestPosts() { - try { - const res = await fetch('/api/blog') - - if (res.status !== 200) return [] - - const { posts } = await res.json() +export function useIssues() { + const { error, ready, result } = useAPICall('/api/github') - return posts - } catch (e) { - console.error(e) - - return [] - } + return { error, ready, result: result && result.issues } } -export async function getLatestTopics() { - try { - const res = await fetch('/api/discourse') - - if (res.status !== 200) return [] +export function usePosts() { + const { error, ready, result } = useAPICall('/api/blog') - const { topics } = await res.json() + return { error, ready, result: result && result.posts } +} - return topics - } catch (e) { - console.error(e) +export function useTopics() { + const { error, ready, result } = useAPICall('/api/discourse') - return [] - } + return { error, ready, result: result && result.topics } } -export async function getCommentsCount(commentsUrl) { - try { - const res = await fetch(`/api/comments?url=${commentsUrl}`) +export function useCommentsCount(commentsUrl) { + const { error, ready, result } = useAPICall( + `/api/comments?url=${commentsUrl}` + ) - if (res.status === 200) { - const { count } = await res.json() - return count - } - } catch (e) { - console.error(e) - } + return { error, ready, result: result && result.count } } From c732ca8f8a1a8d11311f88cc94fab4f7c424d07d Mon Sep 17 00:00:00 2001 From: Ivan Shcheklein Date: Fri, 14 Feb 2020 17:16:59 -0800 Subject: [PATCH 3/7] Update src/components/Community/Learn/index.js Co-Authored-By: Jorge Orpinel --- src/components/Community/Learn/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Community/Learn/index.js b/src/components/Community/Learn/index.js index 5783e71178..78217baa6f 100644 --- a/src/components/Community/Learn/index.js +++ b/src/components/Community/Learn/index.js @@ -251,7 +251,7 @@ export default function CommunityLearn({ theme }) { > {!ready && Loading...} {error && ( - Blog is unavailable right now + Blog unavailable right now )} {posts && posts.map(post => ( From 82c59725751d5d54b99a3590d4e34186512f5f6f Mon Sep 17 00:00:00 2001 From: Ivan Shcheklein Date: Fri, 14 Feb 2020 17:17:08 -0800 Subject: [PATCH 4/7] Update src/components/Community/Meet/index.js Co-Authored-By: Jorge Orpinel --- src/components/Community/Meet/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Community/Meet/index.js b/src/components/Community/Meet/index.js index aea0737410..8e32423c07 100644 --- a/src/components/Community/Meet/index.js +++ b/src/components/Community/Meet/index.js @@ -197,7 +197,7 @@ export default function CommunityMeet({ theme }) { > {!topicsReady && Loading...} {topicsError && ( - Forum is unavailable right now + Forum unavailable right now )} {topics && topics.map(topic => ( From 97cef4a5500c9370efb2cb4d01553eb7fa3762dc Mon Sep 17 00:00:00 2001 From: Ivan Shcheklein Date: Fri, 14 Feb 2020 17:17:14 -0800 Subject: [PATCH 5/7] Update src/components/Community/Meet/index.js Co-Authored-By: Jorge Orpinel --- src/components/Community/Meet/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Community/Meet/index.js b/src/components/Community/Meet/index.js index 8e32423c07..8b682a94af 100644 --- a/src/components/Community/Meet/index.js +++ b/src/components/Community/Meet/index.js @@ -238,7 +238,7 @@ export default function CommunityMeet({ theme }) { > {!issuesReady && Loading...} {issuesError && ( - Github is unavailable right now + Github unavailable right now )} {issues && issues.map(issue => ( From 1d5032cdad7212284859d19662f11419beaf7127 Mon Sep 17 00:00:00 2001 From: Ivan Shcheklein Date: Fri, 14 Feb 2020 17:17:21 -0800 Subject: [PATCH 6/7] Update src/utils/api.js Co-Authored-By: Jorge Orpinel --- src/utils/api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/api.js b/src/utils/api.js index 7c096b950e..0e77d2ddeb 100644 --- a/src/utils/api.js +++ b/src/utils/api.js @@ -22,7 +22,7 @@ const useAPICall = url => { if (!cancelled) { if (res.status !== 200) { - setError('Wrong response types') + setError('Bad response status') } else { setResult(await res.json()) } From 7ed12e5769b88512d82746670749258edfc00b36 Mon Sep 17 00:00:00 2001 From: "restyled-io[bot]" <32688539+restyled-io[bot]@users.noreply.github.com> Date: Fri, 14 Feb 2020 17:19:25 -0800 Subject: [PATCH 7/7] Restyled by prettier (#999) --- src/components/Community/Learn/index.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/Community/Learn/index.js b/src/components/Community/Learn/index.js index 78217baa6f..39862c2bcd 100644 --- a/src/components/Community/Learn/index.js +++ b/src/components/Community/Learn/index.js @@ -250,9 +250,7 @@ export default function CommunityLearn({ theme }) { } > {!ready && Loading...} - {error && ( - Blog unavailable right now - )} + {error && Blog unavailable right now} {posts && posts.map(post => (