From 4db3db2a24735a0bde346c2824f0e6e0c944c2a1 Mon Sep 17 00:00:00 2001 From: DefectingCat Date: Thu, 25 Nov 2021 15:54:35 +0800 Subject: [PATCH] Fix menu list on mobile * add ahooks library * add useAppDispatch and useAppSelector hooks * move out router event handle from useEffect * fix router events off --- app/hooks.ts | 6 ++ components/NavBar.tsx | 111 ++++++++++++++++++++------------- components/PostCard.tsx | 4 +- features/router/routerSlice.ts | 1 + package.json | 1 + pages/_app.tsx | 37 ++++++----- pages/posts/[slug].tsx | 6 +- yarn.lock | 48 +++++++++++++- 8 files changed, 144 insertions(+), 70 deletions(-) create mode 100644 app/hooks.ts diff --git a/app/hooks.ts b/app/hooks.ts new file mode 100644 index 0000000..520e84e --- /dev/null +++ b/app/hooks.ts @@ -0,0 +1,6 @@ +import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'; +import type { RootState, AppDispatch } from './store'; + +// Use throughout your app instead of plain `useDispatch` and `useSelector` +export const useAppDispatch = () => useDispatch(); +export const useAppSelector: TypedUseSelectorHook = useSelector; diff --git a/components/NavBar.tsx b/components/NavBar.tsx index 50a1dd0..6ed6a9f 100644 --- a/components/NavBar.tsx +++ b/components/NavBar.tsx @@ -1,4 +1,4 @@ -import { FC, MouseEvent, useEffect } from 'react'; +import { FC, MouseEvent, useRef } from 'react'; import { Box, Image, @@ -13,9 +13,8 @@ import { Button, } from '@chakra-ui/react'; import UseAnimations from 'react-useanimations'; -import menu2 from 'react-useanimations/lib/menu2'; +import menu3 from 'react-useanimations/lib/menu3'; import { FiHome, FiArchive, FiUser, FiSun, FiMoon } from 'react-icons/fi'; -import Link from 'next/link'; import useGetColors from '../lib/hooks/useGetColors'; import { useRouter } from 'next/router'; @@ -40,28 +39,68 @@ const menu = [ }, ]; +interface MenuListProps { + boxBg: string; + handleMenuClick: ( + // eslint-disable-next-line no-unused-vars + e: MouseEvent, + // eslint-disable-next-line no-unused-vars + path: string + ) => void; +} +const MenuList: FC = ({ boxBg, handleMenuClick }) => { + return ( + + {menu.map((item) => { + return ( + handleMenuClick(e, item.path)} + href={item.path} + key={item.id} + as="a" + alignItems="center" + justifyContent={['unset', null, 'space-between']} + fontSize={['18', null, '22']} + my={['0.5rem', null, '0.5rem']} + cursor="pointer" + > + + {item.name} + + ); + })} + + ); +}; + const NavBar: FC = () => { const router = useRouter(); const [isLargerThan768] = useMediaQuery('(min-width: 768px)'); - const { isOpen, onToggle } = useDisclosure({ defaultIsOpen: true }); + const { isOpen, onToggle } = useDisclosure({ defaultIsOpen: false }); const { colorMode, toggleColorMode } = useColorMode(); const { boxBg, bioColor, textColor, headingColor } = useGetColors(); - useEffect(() => { - if ((isOpen && !isLargerThan768) || (!isOpen && isLargerThan768)) - onToggle(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isLargerThan768]); - + const iconRef = useRef(null); + // Switch pages const handleMenuClick = ( e: MouseEvent, path: string ) => { e.preventDefault(); - !isLargerThan768 && onToggle(); + !isLargerThan768 && + // Click the animate icon. + (iconRef.current?.children[0] as HTMLDivElement).click(); router.push(path); }; @@ -124,36 +163,19 @@ const NavBar: FC = () => { {/* Menu */} - - - {menu.map((item) => { - return ( - handleMenuClick(e, item.path)} - href={item.path} - key={item.id} - as="a" - alignItems="center" - justifyContent={['unset', null, 'space-between']} - fontSize={['18', null, '22']} - my={['0.5rem', null, '0.5rem']} - cursor="pointer" - > - - {item.name} - - ); - })} - - + {/* Mobile menu */} + + + + {/* Desktop menu */} + + + { position={'absolute'} top={'1.5rem'} right={'1rem'} - onClick={onToggle} + ref={iconRef} > diff --git a/components/PostCard.tsx b/components/PostCard.tsx index bd69a11..d5d7f59 100644 --- a/components/PostCard.tsx +++ b/components/PostCard.tsx @@ -4,7 +4,7 @@ import { Box, Flex, Heading, Text, Link } from '@chakra-ui/react'; import { AllPostsData } from '../lib/posts'; import { Icon, Image } from '@chakra-ui/react'; import { FiCalendar, FiTag } from 'react-icons/fi'; -import { useDispatch } from 'react-redux'; +import { useAppDispatch } from '../app/hooks'; import { setFromPath } from '../features/router/routerSlice'; import { useRouter } from 'next/router'; import useGetColors from '../lib/hooks/useGetColors'; @@ -14,7 +14,7 @@ interface Props { } const PostCard: FC = ({ post }) => { - const dispatch = useDispatch(); + const dispatch = useAppDispatch(); const router = useRouter(); const goToPost: MouseEventHandler = (e) => { diff --git a/features/router/routerSlice.ts b/features/router/routerSlice.ts index 42d8b94..e2f4065 100644 --- a/features/router/routerSlice.ts +++ b/features/router/routerSlice.ts @@ -5,6 +5,7 @@ export interface RouterState { } const initialState: RouterState = { + // Record the from path when into the post page. fromPath: '', }; diff --git a/package.json b/package.json index ad9bb9c..cc98cfb 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@emotion/styled": "^11", "@giscus/react": "^1.0.1", "@reduxjs/toolkit": "^1.6.2", + "ahooks": "^2.10.12", "autoprefixer": "^10.3.7", "date-fns": "^2.25.0", "framer-motion": "^5.0.2", diff --git a/pages/_app.tsx b/pages/_app.tsx index 6dca0d1..96d4af6 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -26,24 +26,23 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) { const router = useRouter(); + const handleRouteChange = ( + url: string, + { shallow }: { shallow: 'with' | 'without' } + ) => { + console.log( + `App is changing to ${url} ${ + shallow ? 'with' : 'without' + } shallow routing` + ); + }; + const handleStart = () => { + NProgress.start(); + }; + const handleStop = () => { + NProgress.done(); + }; useEffect(() => { - const handleRouteChange = ( - url: string, - { shallow }: { shallow: 'with' | 'without' } - ) => { - console.log( - `App is changing to ${url} ${ - shallow ? 'with' : 'without' - } shallow routing` - ); - }; - const handleStart = () => { - NProgress.start(); - }; - const handleStop = () => { - NProgress.done(); - }; - router.events.on('routeChangeStart', handleRouteChange); router.events.on('routeChangeStart', handleStart); router.events.on('routeChangeStart', handleStop); @@ -52,8 +51,8 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) { // from the event with the `off` method: return () => { router.events.off('routeChangeStart', handleRouteChange); - router.events.on('routeChangeStart', handleStart); - router.events.on('routeChangeStart', handleStop); + router.events.off('routeChangeStart', handleStart); + router.events.off('routeChangeStart', handleStop); }; }, [router.events]); diff --git a/pages/posts/[slug].tsx b/pages/posts/[slug].tsx index 05277bb..46c65e4 100644 --- a/pages/posts/[slug].tsx +++ b/pages/posts/[slug].tsx @@ -33,11 +33,11 @@ import { useRouter } from 'next/router'; import Footer from '../../components/Footer'; import { Giscus } from '@giscus/react'; import { RootState } from '../../app/store'; -import { useSelector, useDispatch } from 'react-redux'; import { cleanFromPath } from '../../features/router/routerSlice'; import CopyButton from '../../components/post/CopyButton'; import useGetColors from '../../lib/hooks/useGetColors'; import PostImage from '../../components/post/PostImage'; +import { useAppSelector, useAppDispatch } from '../../app/hooks'; export async function getStaticPaths() { const paths = await getAllPostSlugs(); @@ -57,8 +57,8 @@ export const getStaticProps: GetStaticProps = async ({ params }) => { }; const Post = ({ postData }: InferGetStaticPropsType) => { - const fromPath = useSelector((state: RootState) => state.router.fromPath); - const dispatch = useDispatch(); + const fromPath = useAppSelector((state: RootState) => state.router.fromPath); + const dispatch = useAppDispatch(); const router = useRouter(); const goBack = () => { diff --git a/yarn.lock b/yarn.lock index 68095f4..cfcbfd3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,14 @@ # yarn lockfile v1 +"@ahooksjs/use-request@^2.8.13": + version "2.8.13" + resolved "https://registry.npmjs.org/@ahooksjs/use-request/-/use-request-2.8.13.tgz#5ace53859feb6b4fe9ebcbf2e72982bb9b7db383" + integrity sha512-zGSOwGNy6fTudvBcLJ8Ly7DwacEGzQS06fGe1b1mEPWTsK/R6y8ItIbtE2RXTeMoCpbxagamMWo5ZDJkJlmZ6Q== + dependencies: + lodash.debounce "^4.0.8" + lodash.throttle "^4.1.1" + "@babel/code-frame@7.12.11": version "7.12.11" resolved "https://registry.npmmirror.com/@babel/code-frame/download/@babel/code-frame-7.12.11.tgz?cache=0&sync_timestamp=1633554562995&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2F%40babel%2Fcode-frame%2Fdownload%2F%40babel%2Fcode-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" @@ -1290,6 +1298,22 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" +ahooks@^2.10.12: + version "2.10.12" + resolved "https://registry.npmjs.org/ahooks/-/ahooks-2.10.12.tgz#e8cab653039434279e69569a8342c602b3545dab" + integrity sha512-X3nZwr6+CSi1XjGyd/tQU1vF11mNaP4Bo0pdEdUL2ksBURQl0QZvDeUMrKBYHAStq7852P20ycVgu405XxDlFg== + dependencies: + "@ahooksjs/use-request" "^2.8.13" + "@types/js-cookie" "^2.2.6" + dayjs "^1.9.1" + intersection-observer "^0.7.0" + js-cookie "^2.2.1" + lodash.debounce "^4.0.8" + lodash.isequal "^4.5.0" + lodash.throttle "^4.1.1" + resize-observer-polyfill "^1.5.1" + screenfull "^5.0.0" + ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4: version "6.12.6" resolved "https://registry.nlark.com/ajv/download/ajv-6.12.6.tgz?cache=0&sync_timestamp=1631470912358&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fajv%2Fdownload%2Fajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -2187,7 +2211,7 @@ date-fns@^2.25.0: resolved "https://registry.npmmirror.com/date-fns/download/date-fns-2.25.0.tgz?cache=0&sync_timestamp=1633421929609&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fdate-fns%2Fdownload%2Fdate-fns-2.25.0.tgz#8c5c8f1d958be3809a9a03f4b742eba894fc5680" integrity sha1-jFyPHZWL44CamgP0t0LrqJT8VoA= -dayjs@^1.10.4: +dayjs@^1.10.4, dayjs@^1.9.1: version "1.10.7" resolved "https://registry.nlark.com/dayjs/download/dayjs-1.10.7.tgz?cache=0&sync_timestamp=1631266651008&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdayjs%2Fdownload%2Fdayjs-1.10.7.tgz#2cf5f91add28116748440866a0a1d26f3a6ce468" integrity sha1-LPX5Gt0oEWdIRAhmoKHSbzps5Gg= @@ -3532,6 +3556,11 @@ internal-slot@^1.0.3: has "^1.0.3" side-channel "^1.0.4" +intersection-observer@^0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/intersection-observer/-/intersection-observer-0.7.0.tgz#ee16bee978db53516ead2f0a8154b09b400bbdc9" + integrity sha512-Id0Fij0HsB/vKWGeBe9PxeY45ttRiBmhFyyt/geBdDHBYNctMRTE3dC1U3ujzz3lap+hVXlEcVaB56kZP/eEUg== + invariant@^2.2.4: version "2.2.4" resolved "https://registry.nlark.com/invariant/download/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" @@ -3965,6 +3994,16 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.npm.taobao.org/lodash.merge/download/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -3985,6 +4024,11 @@ lodash.sortby@^4.7.0: resolved "https://registry.npm.taobao.org/lodash.sortby/download/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= +lodash.throttle@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" + integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= + lodash.truncate@^4.4.2: version "4.4.2" resolved "https://registry.nlark.com/lodash.truncate/download/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" @@ -5682,7 +5726,7 @@ scheduler@^0.20.2: loose-envify "^1.1.0" object-assign "^4.1.1" -screenfull@^5.1.0: +screenfull@^5.0.0, screenfull@^5.1.0: version "5.2.0" resolved "https://registry.npmmirror.com/screenfull/download/screenfull-5.2.0.tgz?cache=0&sync_timestamp=1635923453416&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fscreenfull%2Fdownload%2Fscreenfull-5.2.0.tgz#6533d524d30621fc1283b9692146f3f13a93d1ba" integrity sha1-ZTPVJNMGIfwSg7lpIUbz8TqT0bo=