따라하며 배우는 리액트 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)
댓글 남기기