#typescript #next-js #tailwindcss

커뮤니티 리스트 생성하기

Oct 31, 2022


커뮤니티 리스트 UI

reddit-clone-app\client\src\pages\index.tsx 파일을 아래와 같이 수정한다.

import type { NextPage } from 'next'
import Link from 'next/link'

const Home: NextPage = () => {
  return (
    <div className='flex max-w-5xl px-4 pt-5 mx-auth'>
      {/* 포스트 리스트 */}
      <div className='w-full md:mr-3 md:w-8/12'></div>

      {/* 사이드바 */}
      <div className='hidden w-4/12 ml-3 md:block'>
        <div className='bg-white border rounded'>
          <div className='p-4 border-b'>
            <p className='text-lg font-semibold text-center'>상위 커뮤니티</p>
          </div>

          {/* 커뮤니티 리스트 */}
          <div></div>
          <div className='w-full py-6 text-center'>
            <Link href="/subs/create">
              <a className='w-full p-2 text-center text-white bg-gray-400 rounded'>
                커뮤니티 만들기
              </a>
            </Link>
          </div>
        </div>
      </div>
    </div>
  )
}

export default Home


커뮤니티 리스트 가져오기

서버 요청 시 axios 대신 swr 모듈을 사용할 예정이다.
swr이 무엇인지는 이후 설명으로 대신하고 아래 명령어를 사용해 swr을 설치한다. reddit-clone-app/client 경로의 터미널에서 아래 명령어를 사용해 설치한다.

npm install swr --save

1. 커뮤니티 리스트 호출 부분

reddit-clone-app\client\src\pages\index.tsx 파일에 아래 내용을 추가한다.

import axios from 'axios';
import type { NextPage } from 'next';
import Link from 'next/link';
import useSWR from 'swr';
import { Sub } from '../types';

const Home: NextPage = () => {
  const fetcher = async (url: string) => {
    return await axios.get(url).then(res => res.data);
  }
  const address = "http://localhost:5000/api/subs/sub/topSubs";
  const { data: topSubs } = useSWR<Sub[]>(address, fetcher)
...생략

2. 커뮤니티 리스트 핸들러 생성

reddit-clone-app\server\src\routes\subs.ts 파일에 아래 내용을 추가한다.

...생략
const topSubs = async (_:Request, res:Response) => {
    try {
        const imageUrlExp = `COALESCE(s."imageUrn", 'http://www.gravatar.com/avatar?d=mp&f=y')`;
        // 쿼리 빌더를 통해 subs 결과를 가져온다
        const subs = await AppDataSource
            .createQueryBuilder()
            .select(`s.title, s.name, ${imageUrlExp} as "imageUrl", count(p.id) as "postCount"`)
            .from(Sub, "s")
            .leftJoin(Post, "p", `s.name = p."subName"`)
            .groupBy('s.titlem, s.name, "imageUrl"')
            .orderBy(`"postCount"`, "DESC")
            .limit(5)
            .execute();
            return res.json(subs);
    } catch (error) {
        console.log(error);
        return res.status(500).json({ error: "문제가 발생했습니다." });
    }
}

const router = Router();

router.post('/', userMiddleware, authMiddleware, createSub);
router.get('/sub/topSubs', topSubs);

export default router;

3. 커뮤니티 리스트 출력하기

reddit-clone-app\client\src\pages\index.tsx 파일에 아래 내용을 추가한다.

... 생략
const Home: NextPage = () => {
  const { authenticated } = useAuthState();

... 생략
          {/* 커뮤니티 리스트 */}
          <div>
            {topSubs?.map((sub) => (
              <div
                key={sub.name}
                className='flex items-center px-4 py-2 text-xs border-b'
              >
                <Link href={`/r/${sub.name}`}>
                  <a>
                    <Image 
                      src={sub.imageUrl}
                      className="rounded-full cursor-pointer"
                      alt="Sub"
                      width={24}
                      height={24}
                    />
                  </a>
                </Link>
                <Link href={`/r/${sub.name}`}>
                  <a className='ml-2 font-bold hover:cursor-pointer'>
                    /r/{sub.name}
                  </a>
                </Link>
                <p className='ml-auth font-medium'>{sub.postCount}</p>
              </div>
            ))}

          // 커뮤니티 만들기 버튼은 로그인 세션이 존재할 때만 출력
          </div>
          {authenticated &&
          <div className='w-full py-6 text-center'>
            <Link href="/subs/create">
              <a className='w-full p-2 text-center text-white bg-gray-400 rounded'>
                커뮤니티 만들기
              </a>
            </Link>
          </div>
          }
... 생략

해당 에러는 Default imagaUrl인 http://www.gravatar.com/avatar?d=mp&f=y를 통해 외부 이미지URL 호출을 차단하기 때문이다.
이를 허용하는 Next.js 설정파일 수정이 필요하다.

reddit-clone-app\client\next.config.js 파일을 아래의 내용으로 수정한다.
수정 내용을 적용하기 위해 Next.js Client App을 재시작한다.

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
  // 추가된 내용
  images:{
    domains: ["www.gravatar.com"]
  }
}

module.exports = nextConfig

[커뮤니티 리스트 출력]



*****

© 2021, Ritij Jain | Pudhina Fresh theme for Jekyll.