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..39862c2bcd 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,6 +10,7 @@ import CommunityBlock from '../Block'
import CommunityButton from '../Button'
import CommunitySection from '../Section'
+import { usePosts, useCommentsCount } from '../../../utils/api'
import { pluralizeComments } from '../../../utils/i18n'
import {
@@ -45,19 +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) {
- fetch(`/api/comments?url=${commentsUrl}`)
- .then(result => result.json())
- .then(data => setCount(data.count))
- }
- }, [])
+ const { error, ready, result } = useCommentsCount(commentsUrl)
return (
@@ -82,14 +74,14 @@ function CommunityBlogPost({
{title}
- {loaded && (
+ {ready && !error && (
<>
- {pluralizeComments(count)}
+ {pluralizeComments(result)}
{' • '}
>
@@ -185,7 +177,9 @@ CommunityDocumentation.propTypes = {
url: PropTypes.string
}
-export default function CommunityLearn({ posts, theme }) {
+export default function CommunityLearn({ theme }) {
+ const { error, ready, result: posts } = usePosts()
+
return (
}
action={
- posts.length && (
+ posts && (
- {posts.length ? (
+ {!ready && Loading...}
+ {error && Blog unavailable right now}
+ {posts &&
posts.map(post => (
- ))
- ) : (
- Blog is unavailable right now
- )}
+ ))}
-
@@ -286,7 +279,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..8b682a94af 100644
--- a/src/components/Community/Meet/index.js
+++ b/src/components/Community/Meet/index.js
@@ -8,6 +8,7 @@ import CommunitySection from '../Section'
import { pluralizeComments } from '../../../utils/i18n'
import { logEvent } from '../../../utils/ga'
+import { useIssues, useTopics } from '../../../utils/api'
import data from '../data'
@@ -110,7 +111,10 @@ CommunityIssue.propTypes = {
color: PropTypes.string
}
-export default function CommunityMeet({ issues, theme, topics }) {
+export default function CommunityMeet({ theme }) {
+ const { erorr: issuesError, ready: issuesReady, result: issues } = useIssues()
+ const { erorr: topicsError, ready: topicsReady, result: topics } = useTopics()
+
return (
}
action={
- topics.length && (
+ topics && (
- {topics.length ? (
+ {!topicsReady && Loading...}
+ {topicsError && (
+ Forum unavailable right now
+ )}
+ {topics &&
topics.map(topic => (
- ))
- ) : (
- Forum is unavailable right now
- )}
+ ))}
-
@@ -217,7 +222,7 @@ export default function CommunityMeet({ issues, theme, topics }) {
}
action={
- issues.length && (
+ issues && (
- {issues.length ? (
+ {!issuesReady && Loading...}
+ {issuesError && (
+ Github unavailable right now
+ )}
+ {issues &&
issues.map(issue => (
- ))
- ) : (
- Github is unavailable right now
- )}
+ ))}
@@ -251,10 +257,8 @@ export default function CommunityMeet({ issues, theme, topics }) {
}
CommunityMeet.propTypes = {
- issues: PropTypes.array,
theme: PropTypes.shape({
backgroundColor: PropTypes.string,
color: PropTypes.string
- }),
- topics: PropTypes.array
+ })
}
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..0e77d2ddeb 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) {
@@ -7,50 +8,64 @@ export function makeAbsoluteURL(req, uri) {
return `${protocol}//${host}${uri}`
}
-export async function getLatestIssues(req) {
- try {
- const res = await fetch(makeAbsoluteURL(req, '/api/github'))
-
- if (res.status !== 200) return []
-
- const { issues } = await res.json()
-
- return issues
- } catch (e) {
- console.error(e)
-
- 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('Bad response status')
+ } else {
+ setResult(await res.json())
+ }
+ }
+ } catch {
+ if (!cancelled) setError('Error loading request')
+ } finally {
+ if (!cancelled) setReady(true)
+ }
+ }
+
+ fetchData()
+
+ return () => {
+ cancelled = true
+ }
+ }, [])
+
+ return { error, ready, result }
}
-export async function getLatestPosts(req) {
- try {
- const res = await fetch(makeAbsoluteURL(req, '/api/blog'))
+export function useIssues() {
+ const { error, ready, result } = useAPICall('/api/github')
- if (res.status !== 200) return []
-
- const { posts } = await res.json()
+ return { error, ready, result: result && result.issues }
+}
- return posts
- } catch (e) {
- console.error(e)
+export function usePosts() {
+ const { error, ready, result } = useAPICall('/api/blog')
- return []
- }
+ return { error, ready, result: result && result.posts }
}
-export async function getLatestTopics(req) {
- try {
- const res = await fetch(makeAbsoluteURL(req, '/api/discourse'))
+export function useTopics() {
+ const { error, ready, result } = useAPICall('/api/discourse')
- if (res.status !== 200) return []
-
- const { topics } = await res.json()
+ return { error, ready, result: result && result.topics }
+}
- return topics
- } catch (e) {
- console.error(e)
+export function useCommentsCount(commentsUrl) {
+ const { error, ready, result } = useAPICall(
+ `/api/comments?url=${commentsUrl}`
+ )
- return []
- }
+ return { error, ready, result: result && result.count }
}