따라하며 배우는 리액트 A-Z
[프론트엔드, 웹 개발] 강의입니다.
이 강의를 통해 리액트 기초부터 중급까지 배우게 됩니다. 하나의 강의로 개념도 익히고 실습도 하며, 리액트를 위해 필요한 대부분의 지식을 한번에 습득할 수 있도록 만들었습니다.
✍️
이런 걸
배워요!
리액트
NextJS
타입스크립트
정적 사이트 자동 배포
도커
강의: https://www.inflearn.com/course/%EB%94%B0%EB%9D%BC%ED%95%98%EB%8A%94-%EB%A6%AC%EC%95%A1%ED%8A%B8#
강의 자료 : https://github.com/braverokmc79/DiagramPDF
소스 :
https://github.com/braverokmc79/react-button-app
[7]. Next.js와 TypeScript
84. TypeScript Type
강의:
https://www.inflearn.com/course/따라하는-리액트/unit/119930?tab=curriculum
85. Typescript 추가 제공 타입
강의:
https://www.inflearn.com/course/따라하는-리액트/unit/119931?tab=curriculum
86. Type annotation, Type inference
강의:
www.inflearn.com/course/따라하는-리액트/unit/119932?tab=curriculum
87. Type assertion
강의:
www.inflearn.com/course/따라하는-리액트/unit/119933?tab=curriculum
88. getStaticProps를 이용한 포스트 리스트 나열
강의:
www.inflearn.com/course/따라하는-리액트/unit/119934?tab=curriculum
lib/post.ts
import fs from 'fs' import path from 'path' import matter from 'gray-matter' const postsDirectory =path.join(process.cwd(), 'posts'); export function getSortedPostsData(){ console.log( " getSortedPostsData "); // posts 파일 이름을 잡아주기 const fileNames =fs.readdirSync(postsDirectory); //['pre-redndering.md' , ...] const allPostsData =fileNames.map(fileName => { const id=fileName.replace(/\.md$/, ""); const fullPath =path.join(postsDirectory, fileName); const fileContents =fs.readFileSync(fullPath, 'utf-8'); const matterResult =matter(fileContents); return{ id, ...(matterResult.data as {data :string; title:string}) } }) console.log(allPostsData); return allPostsData.sort((a, b) =>{ if(a.date <b.date){ return 1; }else{ return -1; } }); }
src/pages/index.tsx
import Head from 'next/head' import { Inter } from '@next/font/google' import homeStyles from '@/styles/Home.module.css' import { GetStaticProps } from 'next' import {getSortedPostsData} from "../../lib/post"; const inter = Inter({ subsets: ['latin'] }) export default function Home({ allPostsData }: { allPostsData: { date: string title: string id: string }[] }) { console.log( " postValue 내용: " , allPostsData); return ( <> <Head> <title>JUNHO CHOI</title> <meta name="description" content="Generated by create next app" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="icon" href="/favicon.ico" /> </Head> <section className={homeStyles.headingMd}> <p>[Macaronics Introduction]</p> </section> <section className={`${homeStyles.headingMd} ${homeStyles.padding1px}`}> <h2 className={homeStyles.headingLg}>Blog</h2> <ul className={homeStyles.list}> {allPostsData.map(({id, title, date})=> <li className={homeStyles.listItem} key={id}> <a>{title}</a> <br/> <small className={homeStyles.lightText}> {date} </small> </li> )} </ul> </section> </> ) } export const getStaticProps: GetStaticProps = async () => { const allPostsData = getSortedPostsData() return { props: { allPostsData } } }
89.포스트 자세히 보기 페이지로 이동(file system 기반의 라우팅)
강의:
www.inflearn.com/course/따라하는-리액트/unit/119935?tab=curriculum
src/pages/posts/[id].tsx
import React from 'react' export default function Post() { return ( <div>[id]</div> ) }
src/pages/index.tsx
~ <ul className={homeStyles.list}> {allPostsData.map(({id, title, date})=> <li className={homeStyles.listItem} key={id}> <Link href={`/posts/${id}`}> {title} </Link> <br/> <small className={homeStyles.lightText}> {date} </small> </li> )} </ul> ~
90.포스트 데이터를 가져와서 보여주기(remark)
강의:
www.inflearn.com/course/따라하는-리액트/unit/119936?tab=curriculum
src/pages/posts/[id].tsx
import { getAllPostIds, getPostData } from 'lib/post'; import Head from 'next/head' import homeStyles from '../../styles/home.module.css' import { GetStaticProps } from 'next'; import React from 'react' export default function Post({ postData } : { postData:{ title:string, date:string, contntHtml :string } }) { return ( <div> <Head> <title>{postData.title}</title> </Head> <article> <h1 className={homeStyles.headingXl}>{postData.title}</h1> <div className={homeStyles.lightText}> {postData.date} </div> <div dangerouslySetInnerHTML={{ __html: postData.contentHtml }} /> </article> </div> ) } export const getStaticPaths: GetStatiPaths = async ()=>{ const paths =getAllPostIds(); console.log( 'paths ' , paths); return{ paths, fallback:false } } // paths [ { params: { id: 'pre-rendering' } }, { params: { id: 'ssg-ssr' } } ] // params { id: 'pre-rendering' } export const getStaticProps : GetStaticProps = async ({params}) =>{ console.log('params ' , params); const postData = await getPostData(params.id as string); return{ props:{ postData } } }
lib/post.ts
import fs from 'fs' import path from 'path' import matter from 'gray-matter' import { remark } from 'remark' import html from 'remark-html' const postsDirectory =path.join(process.cwd(), 'posts'); export function getSortedPostsData(){ // posts 파일 이름을 잡아주기 const fileNames =fs.readdirSync(postsDirectory); //['pre-redndering.md' , ...] const allPostsData =fileNames.map(fileName => { const id=fileName.replace(/\.md$/, ""); const fullPath =path.join(postsDirectory, fileName); const fileContents =fs.readFileSync(fullPath, 'utf-8'); const matterResult =matter(fileContents); return{ id, ...(matterResult.data as {data :string; title:string}) } }) return allPostsData.sort((a, b) =>{ if(a.date <b.date){ return 1; }else{ return -1; } }); } export function getAllPostIds(){ const fileNames =fs.readdirSync(postsDirectory); return fileNames.map(fileName=>{ return{ params:{ id:fileName.replace(/\.md$/, '') } } }) } export async function getPostData(id :string){ const fullPath =path.join(postsDirectory, `${id}.md`); const fileContents =fs.readFileSync(fullPath, 'utf8'); //Use gray-matter to parse the post metadata section const matterResult =matter(fileContents); //Use remark to convert markdown into HTML string const processedContent =await remark() .use(html).process(matterResult.content) const contentHtml =processedContent.toString(); return{ id, contentHtml, ...(matterResult.data as {date :string; title:string}) } }
91.블로그앱 스타일링
강의:
www.inflearn.com/course/따라하는-리액트/unit/119937?tab=curriculum
댓글 ( 4)
댓글 남기기