AWS EC2 인스턴스 생성 AWS 계정을 생성하고 EC2 인스턴스를 프리티어(무료)로 사용하는 방법에 대해서는 사전에 블로그에 작성한 포스트를 참고하면 된다. 해당 포스트에서는 아마존 리눅스 2 이미지를 사용해 서버를 구성했으므로 필요에 따라 다른 이미지를 선택해도 무방하다. 무료로 AWS EC2 인스턴스 사용하기(프리 티어) AWS에 Docker 설치 내가 사용하는 AWS 서버 OS 이미지는 아마존...
유저 페이지 완성 UI 유저 페이지 생성 유저 페이지의 context path는 /u/[username]의 형태를 갖도록 한다. 이를 위해 reddit-clone-app\client\src\pages\u\[username].tsx 파일을 생성하고 아래 내용을 입력한다. import UserPage from 'react' const UserPage = () => { const router = useRouter(); // 사용자 이름을 URL에서 가져옴 const username = router.query.username; // swr 요청을 사용해...
Intersection observer 화면에 DOM 엘리먼트가 교차되는 것을 감시하고 개발자가 정의한 부분만큼 교차되었을 때 원하는 로직을 실행하기 위해 사용한다. threshold는 DOM엘리먼트가 뷰포트와 교차된 비율을 의미하며 해당 비율만큼 교차되었을 때 구문이 실행됨을 의미한다. 마지막 포스트가 화면에 교차되었을 때 다음 포스트 가져오기 reddit-clone-app\client\src\pages\index.tsx 파일에 아래 내용을 추가한다. ...생략 // 현재 감시중인 ELEMENT의 id값...
useSWRInfinite 이란 [useSWRInfinite 문서] https://swr.vercel.app/ko/docs/pagination#useswrinfinite SWR은 페이지 매김 및 무한 로딩과 같은 일반적인 UI 패턴을 지원하기 위해 전용 API useSWRInfinite를 제공한다. 무한 스크롤 UI패턴의 경우 지속적으로 다음 페이지 데이터를 가져오기 위한 용도로 사용된다. [useSWRInfinite 반환 값] data : 요청을 통해 각 페이지 응답 값의 배열 error : useSWR의 error와 동일...
포스트 나열하기 커뮤니티 상세 페이지 진입 시 해당 커뮤니티에 작성된 포스트들을 나열하기 위해 커뮤니티 상세 페이지 reddit-clone-app\client\src\pages\r\[sub].tsx 파일에 아래 내용을 추가한다. ...생략 import PostCard from '../../components/PostCard'; ...생략 let renderPosts; if(!sub) { // 커뮤니티 존재하지 않을 때 renderPosts = <p className='text-lg text-center'>로딩중...</p> } else if(sub.posts.length === 0) { // 포스트가 없을...
투표 적용 시 즉시 업데이트 코멘트와 마찬가지로 useSWR 사용 구문에서 mutate를 가져오고 이를 투표 요청하는 vote함수에서 실행해주면 된다. reddit-clone-app\client\src\pages\r\[sub]\[identifier]\[slug].tsx 파일에 아래 내용을 추가해 본다. ...생략 const { data: post, error, mutate } = useSWR<Post>(identifier && slug ? `/posts/${identifier}/${slug}` : null) ...생략 const vote = async (value: number, comment?:Comment) => {...
포스트, 코멘트 투표 UI 포스트와 코멘트 투표 완성 UI는 아래와 같다 포스트, 코멘트 투표 UI 템플릿 작성 포스트 내용 페이지 내 포스트, 코멘트 투표 UI를 추가해야 하므로 reddit-clone-app\client\src\pages\r\[sub]\[identifier]\[slug].tsx 파일에 아래 내용을 추가한다. [포스트 투표 부분] ...생략 {post && ( <> <div className="flex"> {/* 투표 가능 부분 */} <div className="flex-shrink-0 w-10...
useSWR mutate 란? 캐시 된 데이터를 개발자가 원하는 시점에서 갱신하기 위한 함수이다. useSWRConfig() hook으로부터 mutate 함수를 얻을 수 있으며, mutate(key)를 호출하여 동일한 키를 사용하는 다른 SWR hook*에게 갱신 메시지를 전역으로 브로드캐스팅할 수 있습니다. 포스트 코멘트 작성에서 mutate 적용 현재 댓글 작성 후 작성한 코멘트가 즉시 화면에 갱신되지 않는다. 새로고침을 수행하면...
코멘트 리스트 가져오기 포스트 내용 페이지 진입 시 SWR을 사용해서 해당 포스트에 작성된 코멘트를 가져온다. reddit-clone-app\client\src\pages\r\[sub]\[identifier]\[slug].tsx 파일에 아래 내용을 추가한다. ...생략 const PostPage = () => { const router = useRouter(); const { identifier, sub, slug } = router.query; const { authenticated, user } = useAuthState(); const [ newComment, setNewComment...
포스트 댓글 UI 로그인 된 상태에서는 댓글 작성이 가능하도록, 로그인이 되지 않은 상태에서는 댓글 작성을 위해 로그인 해주세요 메시지를 출력한다. 완성된 UI는 아래와 같다. 포스트 댓글 UI 템플릿 작성 댓글은 포스트 내용 페이지에 진입 시 작성할 수 있어야 하므로 reddit-clone-app\client\src\pages\r\[sub]\[identifier]\[slug].tsx 파일에 템플릿을 아래와 같이 추가한다. ...생략 // 로그인 여부에 따라...
포스트 페이지 결과 UI 포스트 페이지 생성 포스트 페이지의 context path는 /r/{SubName}/{identifier}/{slug}의 형태를 띌 것이므로 reddit-clone-app\client\src\pages\r\[sub]\[identifier]\[slug].tsx 파일을 생성하고 아래 내용을 입력한다. import axios from "axios"; import { useRouter } from "next/router" import useSWR from 'swr' import { Post } from "../../../../types"; const PostPage = () => { const router =...
포스트 Create 페이지 기능 앞서 생성했던 포스트 Create 생성 페이지에서 생성하기 버튼을 통해 form 태그의 onSubmit 이벤트가 발생했을 때 동작하게 될 submitPost 함수를 아래와 같이 추가한다. reddit-clone-app\client\src\pages\r\[sub]\create.tsx ...생략 // 페이지 URL내의 커뮤니티 이름(subName)을 사용하기 위해 추가 const router = useRouter(); const { sub: subName } = router.query; const submitPost= async...
포스트 Create 페이지 UI 포스트 Create 페이지 UI 구현 포스트 Create 페이지의 context path를 /r/{커뮤니티명}/create 으로 해주기 위해 reddit-clone-app\client\src\pages\r\[sub]\create.tsx 경로에 파일을 생성한다. 아래의 내용을 입력한다. import axios from 'axios'; import { GetServerSideProps } from 'next'; import React, { useState } from 'react' const PostCreate = () => { // 포스트...
사이드 바 컴포넌트 생성, 적용 reddit-clone-app\client\src\components\SideBar.tsx 경로에 파일을 생성하고 아래 내용을 입력한다. import dayjs from 'dayjs'; import Link from 'next/link'; import React from 'react' import { useAuthState } from '../context/auth'; const SideBar = ({ sub }) => { const { authenticated } = useAuthState(); return ( <div className='hidden w-4/12 ml-3...
ref를 사용하여 이미지 올리기 먼저 DOM상에 이미지 파일을 업로드하기 위해 reddit-clone-app\client\src\pages\r\[sub].tsx 파일에 아래 내용을 추가해준다. import React, { ChangeEvent, useEffect, useRef, useState } from 'react'; ...생략 const fileInputRef = useRef<HTMLInputElement>(null); ...생략 return ( <> {sub && <> <div> // 추가 부분 <input type="file" hidden={true} ref={fileInputRef} onChange={uploadImage} /> ...생략 fileInputRef :...
커뮤니티 상세 페이지 UI 템플릿 reddit-clone-app\client\src\pages\r\[sub].tsx 경로의 파일을 생성하고 아래 내용을 입력한다. import axios from 'axios' import { useRouter } from 'next/router'; import React from 'react' import useSWR from 'swr'; const SubPage = () => { const fetcher = async (url: string) => { try { const res = await...
커뮤니티 리스트 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'>...
상단바 UI 생성 import axios from 'axios'; import Link from 'next/link' import React from 'react' import { useAuthDispatch, useAuthState } from '../context/auth' const NavBar: React.FC = () => { const { loading, authenticated } = useAuthState(); const dispatch = useAuthDispatch(); const handleLogout = () => { axios.post("/auth/logout") .then(() => {...
인증에 따른 제한 현재 로그인 전 브라우저 쿠키에 token이 없는 상태로 /subs/create 페이지에 접속이 가능하다. 인증되지 않은 사용자가 커뮤니티 생성 페이지에 접근이 가능하다는 것이다. 이러한 문제점을 해결하기 위해 Next.js의 getServerSideProps를 사용한다. reddit-clone-app\client\src\pages\subs\create.tsx 파일에 아래 내용을 추가한다. ...생략 // 서버 사이드 렌더링으로 서버 요청 시 데이터를 불러온다 export const getServerSideProps: GetServerSideProps...
State 생성 reddit-clone-app\client\src\pages\subs\create.tsx 파일에서 이전에 UI를 위한 템플릿을 작성했다. UI의 기능 구현을 위해 State를 선언하고 필요 모듈을 import한다. // 필요 모듈 선언 useRouter, useState, axios import axios from 'axios'; import { useRouter } from 'next/router'; import React, { FormEvent, useState } from 'react' import InputGroup from '../../components/InputGroup' const SubCreate =...
커뮤니티 생성 페이지 UI 현재 개발하고 있는 Reddit-clone-app에서 커뮤니티를 생성하는 페이지의 UI는 아래와 같다. 커뮤니티 생성 페이지 UI 파일 생성 reddit-clone-app\client\src\pages\subs\create.tsx 폴더 구조와 파일을 생성하고, 아래 소스를 입력한다. 구분 폴더명이 subs인 이유는 Reddit 서비스에서 커뮤니티를 Subreddits 라고 지칭하기 때문이다. import React from 'react' import InputGroup from '../../components/InputGroup' const SubCreate =...
사용자 정보를 Context에 담아 사용하는 이유 React Context를 사용하지 않고 User정보를 각각의 React 컴포넌트에서 사용하기 위해서는 컴포넌트 간 User 정보를 주고 받는 작업이 매번 이루어진다. 그러나 React Context에서 User 정보를 관리하게 되면 컴포넌트 간 데이터를 주고 받을 필요 없이 로그인 후 언제든 React Context에서 User 정보를 사용 가능하다. React Context...
로그인 후 Client Cookie 처리 로그인 요청 후 response 쿠기에 정상적으로 jwt 토큰이 담겨 오는 것을 확인했다. 그러나 개발자도구 > Application 탭 내 jwt 토근이 저장되지 않는다. 이유는 Server에서 로그인 후 response 객체에 쿠키를 Set 하는 과정에서 옵션넣어줘야 한다. reddit-clone-app\server\src\routes\auth.ts 파일에 아래 내용을 추가한다. ...생략 const login = async (req...
로그인 페이지 기능 생성 reddit-clone-app\client\src\pages\login.tsx 파일에 아래의 내용을 추가한다. import Axios from 'axios'; ...생략 import React, { FormEvent, useState } from 'react' ...생략 const login = () => { // State 생성 const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const [errors, setErrors] = useState<any>({}); // handleSubmit 함수...
로그인 페이지 UI 생성 reddit-clone-app\client\src\pages\login.tsx 파일을 생성하고 아래의 내용으로 편집한다. import React from 'react' import InputGroup from '../components/InputGroup' const Login = () => { return ( <div className='bg-white'> <div className='flex flex-col items-center justify-center h-screen p-6'> <div className='w-10/12 mx-auto md:w-96'> <h1 className='mb-2 text-lg font-medium'>로그인</h1> <form onSubmit={handleSubmit}> <InputGroup placeholder='Username' value={username} setValue={setUsername} error={errors.username}...
register.tsx 코드 작성 import Link from 'next/link' import React, {useState} from 'react' import InputGroup from '../components/InputGroup' const Register = () => { const [email, setEmail] = useState(""); const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const [errors, setErrors] = useState<any>({}); return ( <div className="bg-white"> <div className='flex flex-col items-center...
회원가입 UI 페이지 완성 모습 register.tsx 파일 생성 reddit-clone-app/client/src/pages/register.tsx 파일을 생성한다. UI를 다음과 같이 작성한다. import Link from 'next/link' import React from 'react' const register = () => { return ( <div className="bg-white"> <div className='flex flex-col items-center justify-center h-screen p-6'> <div className='w-10/12 mx-auto md:w-96'> <h1 className='mb-2 text-lg font-medium'>회원가입</h1> <form> <button...
Tailwind CSS 적용을 위한 모듈 설치하기 reddit-clone-app/client 경로에서 npm 모듈 설치 npm i -D postcss-preset-env tailwindcss Tailwind 설정 파일 생성 reddit-clone-app/client 경로 터미널에서 아래 명령어 입력 npx tailwind init 아래와 같이 tailwind.config.js 파일이 생성됩니다. PostCSS 빌드 적용을 위한 postcss 설정 파일 생성 reddit-clone-app/client 경로 터미널에서 아래 명령어 입력 touch postcss.config.js...
No projects with this tag.