From 50b8e1a89de0b7654b65c85af6dec7aef8ef37af Mon Sep 17 00:00:00 2001 From: Junho Baik Date: Thu, 30 Jul 2020 01:36:46 +0900 Subject: [PATCH] =?UTF-8?q?Post,=20Comment=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20Lazy=20load=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9=20#64?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 포스트 페이지 로드에 disqus 생성이 함께 되면서 느림, 따라서 스크롤을 하여 포스트 내용의 아래에 도달하게 된 시점에 React.lazy를 이용하여 컴포넌트를 불러오게 되는 방식으로 개선 --- src/components/Comment/index.tsx | 29 ++++++++ src/templates/Post.tsx | 114 ++++++++++++++++--------------- 2 files changed, 89 insertions(+), 54 deletions(-) create mode 100644 src/components/Comment/index.tsx diff --git a/src/components/Comment/index.tsx b/src/components/Comment/index.tsx new file mode 100644 index 000000000..8244fa85b --- /dev/null +++ b/src/components/Comment/index.tsx @@ -0,0 +1,29 @@ +import * as React from 'react'; +import { DiscussionEmbed } from 'disqus-react'; +import config from '../../../_config'; + +interface CommentProps { + slug: string; + title: string; +} + +const Comment = ({ slug, title }: CommentProps) => { + console.log('Comment'); + + const disqusConfig = { + shortname: config.disqusShortname, + config: { + url: `${config.siteUrl + slug}`, + identifier: slug, + title, + }, + }; + + return ( +
+ +
+ ); +}; + +export default Comment; diff --git a/src/templates/Post.tsx b/src/templates/Post.tsx index 95226053e..40c5dce5e 100644 --- a/src/templates/Post.tsx +++ b/src/templates/Post.tsx @@ -1,11 +1,10 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import * as React from 'react'; -import { useEffect, useState } from 'react'; +import { useEffect, useState, Suspense } from 'react'; import Helmet from 'react-helmet'; import { useSelector } from 'react-redux'; import { graphql, Link } from 'gatsby'; -import { DiscussionEmbed } from 'disqus-react'; import moment from 'moment'; import { FontAwesomeIcon as Fa } from '@fortawesome/react-fontawesome'; import { faListUl, faLayerGroup, faAngleLeft } from '@fortawesome/free-solid-svg-icons'; @@ -24,13 +23,13 @@ import { PocketIcon, EmailIcon, } from 'react-share'; +import _ from 'lodash'; import { RootState } from '../state/reducer'; import Layout from '../components/Layout'; import Toc from '../components/Toc'; import SEO from '../components/seo'; - import 'katex/dist/katex.min.css'; import './code-theme.scss'; import './post.scss'; @@ -62,18 +61,44 @@ const Post = (props: postProps) => { const [yList, setYList] = useState([] as number[]); const [isInsideToc, setIsInsideToc] = useState(false); + const [commentEl, setCommentEl] = useState(); const isTableOfContents = enablePostOfContents && tableOfContents !== ''; const isDevelopment = process.env.NODE_ENV === 'development'; const isDisqus: boolean = disqusShortname ? true : false; const isSocialShare = enableSocialShare; - useEffect(() => { - const hs = Array.from(document.querySelectorAll('h2, h3')) as HTMLHeadingElement[]; - const minusValue = window.innerHeight < 500 ? 100 : Math.floor(window.innerHeight / 5); - const yPositions = hs.map(h => h.offsetTop - minusValue); - setYList(yPositions); - }, []); + const mapTags = tags.map((tag: string) => { + return ( +
  • + {`#${tag}`} +
  • + ); + }); + + const mapSeries = series.map((s: any) => { + return ( +
  • + + {s.title} +
    {slug === s.slug ? : null}
    + +
  • + ); + }); + + const metaKeywords: (keywordList: string[], tagList: string[]) => string[] = ( + keywordList: string[], + tagList: string[] + ) => { + const resultKeywords = new Set(); + + for (const v of [...keywordList, ...tagList]) { + resultKeywords.add(v); + } + + return Array.from(resultKeywords) as string[]; + }; useEffect(() => { if (isMobile) { @@ -114,47 +139,32 @@ const Post = (props: postProps) => { }; }, [yList]); - const mapTags = tags.map((tag: string) => { - return ( -
  • - {`#${tag}`} -
  • - ); - }); - - const mapSeries = series.map((s: any) => { - return ( -
  • - - {s.title} -
    {slug === s.slug ? : null}
    - -
  • - ); - }); - - //disqus - const disqusConfig = { - shortname: config.disqusShortname, - config: { - url: `${config.siteUrl + slug}`, - identifier: slug, - title, - }, - }; - - const metaKeywords: (keywordList: string[], tagList: string[]) => string[] = ( - keywordList: string[], - tagList: string[] - ) => { - const resultKeywords = new Set(); + useEffect(() => { + // scroll + const postContentOriginTop = document.querySelector('.blog-post')?.getBoundingClientRect().top ?? 0; + const removeScrollEvent = () => document.removeEventListener('scroll', scrollEvents); + const renderComment = () => { + const Comment = React.lazy(() => import('../components/Comment')); + setCommentEl(); + }; + const scrollEvents = _.throttle(() => { + const postContentHeight = document.querySelector('.blog-post')?.getBoundingClientRect().height ?? Infinity; + if (window.scrollY + window.innerHeight - postContentOriginTop > postContentHeight) { + renderComment(); + removeScrollEvent(); + } + }, 250); + scrollEvents(); + document.addEventListener('scroll', scrollEvents); - for (const v of [...keywordList, ...tagList]) { - resultKeywords.add(v); - } + // toc + const hs = Array.from(document.querySelectorAll('h2, h3')) as HTMLHeadingElement[]; + const minusValue = window.innerHeight < 500 ? 100 : Math.floor(window.innerHeight / 5); + const yPositions = hs.map(h => h.offsetTop - minusValue); + setYList(yPositions); - return Array.from(resultKeywords) as string[]; - }; + return () => removeScrollEvent(); + }, []); return ( <> @@ -301,7 +311,7 @@ const Post = (props: postProps) => { ) : null} - {isDevelopment ? ( + {!isDevelopment ? ( <> - {isDisqus ? ( -
    - -
    - ) : null} + }>{commentEl} )}