diff --git a/frontend/lecture/src/components/StackBadge/index.tsx b/frontend/lecture/src/components/StackBadge/index.tsx
new file mode 100644
index 0000000..1ef4ffa
--- /dev/null
+++ b/frontend/lecture/src/components/StackBadge/index.tsx
@@ -0,0 +1,54 @@
+export const StackBadge = ({
+ stack,
+}: {
+ stack:
+ | 'Zustand'
+ | 'Jotai'
+ | 'Redux'
+ | 'Tanstack Query'
+ | 'SWR'
+ | 'Recoil'
+ | 'MobX'
+ | 'Sangte'
+ | 'Redux Toolkit'
+ | 'React'
+ | 'Claude Sonnet'
+ | 'v0'
+ | 'CSS'
+ | 'styled-components'
+ | 'emotion'
+ | 'Tailwind CSS';
+}) => {
+ const image = {
+ Zustand:
+ 'https://user-images.githubusercontent.com/958486/218346783-72be5ae3-b953-4dd7-b239-788a882fdad6.svg',
+ Jotai: 'https://cdn.candycode.com/jotai/jotai-mascot.png',
+ Redux: 'https://redux.js.org/img/redux.svg',
+ 'Tanstack Query':
+ 'https://seeklogo.com/images/R/react-query-logo-1340EA4CE9-seeklogo.com.png',
+ SWR: null,
+ Recoil:
+ 'https://d2eip9sf3oo6c2.cloudfront.net/tags/images/000/001/298/square_480/recoil.png',
+ MobX: 'https://mobx.js.org/assets/mobx.png',
+ Sangte:
+ 'https://www.npmjs.com/npm-avatar/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdmF0YXJVUkwiOiJodHRwczovL3MuZ3JhdmF0YXIuY29tL2F2YXRhci8yYjIzMTU0NTBkZjRmNzc3MmM0NTA5ZWQxNDEwNmI1OD9zaXplPTQ5NiZkZWZhdWx0PXJldHJvIn0.sJRQi6w4lEc74LfDpbf1VwBxVP8KEBuqEz601WqDH1s',
+ 'Redux Toolkit': 'https://redux.js.org/img/redux.svg',
+ React:
+ 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQo8BG6UD3b_Fowh4gtwIjw2GPTWQQ30uBy-w&s',
+ 'Claude Sonnet':
+ 'https://qph.cf2.poecdn.net/main-thumb-pb-1019-200-ecyfizaydihfkxfwhwjlruyjdyoxengr.jpeg',
+ v0: 'https://v0.dev/apple-icon.png?0ef31a19cc582b82',
+ CSS: 'https://upload.wikimedia.org/wikipedia/commons/thumb/6/62/CSS3_logo.svg/768px-CSS3_logo.svg.png',
+ 'styled-components': 'https://styled-components.com/logo.png',
+ emotion: 'https://avatars.githubusercontent.com/u/31557565?s=200&v=4',
+ 'Tailwind CSS':
+ 'https://seeklogo.com/images/T/tailwind-css-logo-5AD4175897-seeklogo.com.png',
+ }[stack];
+
+ return (
+
+ {image !== null && }
+ {stack}
+
+ );
+};
diff --git a/frontend/lecture/src/lectures/Architecture/index.tsx b/frontend/lecture/src/lectures/Architecture/index.tsx
index 7d428c3..c112a5e 100644
--- a/frontend/lecture/src/lectures/Architecture/index.tsx
+++ b/frontend/lecture/src/lectures/Architecture/index.tsx
@@ -6,6 +6,7 @@ import { CodeSnippet } from '@/components/CodeSnippet';
import { Description } from '@/components/Description';
import { ExternalLink } from '@/components/ExternalLink';
import { Slides } from '@/components/Slides';
+import { StackBadge } from '@/components/StackBadge';
import { getLectureItem } from '@/lectures';
export const architectureLecture = getLectureItem({
@@ -46,7 +47,10 @@ export const architectureLecture = getLectureItem({
특히 요즘은 AI가 굉장히 빠르게 발전하고 있어서, 만드는 건{' '}
진짜 누구나 합니다
-
Claude Sonnet, v0 등등
+
+ , {' '}
+ 등등
+
(개인 생각) 점점 개발자의 역량은
잘 만드는 것 +
문제를 풀어내는 역량이 중요해질 것
diff --git a/frontend/lecture/src/lectures/Future/index.tsx b/frontend/lecture/src/lectures/Future/index.tsx
new file mode 100644
index 0000000..9a9f93a
--- /dev/null
+++ b/frontend/lecture/src/lectures/Future/index.tsx
@@ -0,0 +1,9 @@
+import { Slides } from '@/components/Slides';
+import { getLectureItem } from '@/lectures';
+
+export const futureLecture = getLectureItem({
+ title: '프론트엔드의 현재와 미래',
+ description: '기술 동향 파악하기, 생태계에 참여하기',
+ date: new Date('2024-11-20 20:30:00'),
+ element:
,
+});
diff --git a/frontend/lecture/src/lectures/Performance/index.tsx b/frontend/lecture/src/lectures/Performance/index.tsx
index 37a71a4..2c6d5b2 100644
--- a/frontend/lecture/src/lectures/Performance/index.tsx
+++ b/frontend/lecture/src/lectures/Performance/index.tsx
@@ -145,7 +145,22 @@ export const performanceLecture = getLectureItem({
},
{ title: '로딩 속도 개선: 용량 줄이기', content:
TBD
},
{ title: '로딩 속도 개선: 스켈레톤 ui', content:
TBD
},
- { title: '로딩 속도 개선: 이미지 최적화', content:
TBD
},
+ {
+ title: '로딩 속도 개선: SSR (1) CSR 방식에 대한 이해',
+ content:
TBD
,
+ },
+ {
+ title: '로딩 속도 개선: SSR (2) SSR?',
+ content:
TBD
,
+ },
+ {
+ title: '로딩 속도 개선: SSR (3) 서버 컴포넌트',
+ content:
TBD
,
+ },
+ {
+ title: '로딩 속도 개선: SSR (4) 만능일까?',
+ content:
비용, 서버 리소스 관리, 프레임워크에 결합
,
+ },
]}
/>
),
diff --git a/frontend/lecture/src/lectures/StateManagement/index.tsx b/frontend/lecture/src/lectures/StateManagement/index.tsx
index dfdde58..0b6d7db 100644
--- a/frontend/lecture/src/lectures/StateManagement/index.tsx
+++ b/frontend/lecture/src/lectures/StateManagement/index.tsx
@@ -1,9 +1,311 @@
+import { Callout } from '@/components/Callout';
+import { CodeSnippet } from '@/components/CodeSnippet';
+import { ExternalLink } from '@/components/ExternalLink';
+import { InlineCode } from '@/components/InlineCode';
import { Slides } from '@/components/Slides';
+import { StackBadge } from '@/components/StackBadge';
import { getLectureItem } from '@/lectures';
export const stateManagementLecture = getLectureItem({
title: '상태 관리',
description: '전역 상태 관리, Redux, React Query',
date: new Date('2024-10-16 20:30:00'),
- element:
,
+ element: (
+
+
+ 앞으로 여러 상태 관리 도구들을 만나게 될 텐데, 조금 더 친숙하게
+ 공부할 수 있게 배경을 잡는다
+
+
+ 각 상태 관리 도구의 사용법을 다루진 않습니다. 과제에서도 다루지
+ 않습니다.
+
+
+ 리액트 경험이 충분하지 않다면 다소 뜬구름 잡는 이야기로 들릴 수
+ 있습니다만, 그렇다고 안 할 수는 없는 이야기입니다.
+
+ 역사 얘기라고 생각하고 편하게 들어주세요
+
+ ),
+ },
+ {
+ title: '상태 관리',
+ content: (
+
+
+ 세미나 1에서, 상태는 의 핵심 개념
+ 중 하나라고 했었음
+
+
+ 따라서 상태를 잘 관리하는 게 중요하고, 사람들이 많이 어려워하는
+ 것 중 하나
+
+
+ 이를 돕기 위한 여러 도구들이 존재하며, 사실상 상태관리 도구 없이
+ 어플리케이션을 만드는 건 쉽지 않다
+
+
여러분도 토이프로젝트 가시면 뭐 하나는 쓰셔야 할 거예요
+
+ ),
+ },
+ {
+ title: 'Redux (2015~현재)',
+ content: (
+
+
+ 2020년까지만 해도, 사실상 를 한다 =={' '}
+ 를 한다 였다
+
+
+ 그 시절 코드
+
+
`,
+ ` User Data
`,
+ ` Username: {username}
`,
+ ` Email: {email}
`,
+ ` `,
+ ` `,
+ ` );`,
+ ` }`,
+ `}`,
+ ``,
+ `const mapStateToProps = (state) => ({`,
+ ` username: state.user.username,`,
+ ` email: state.user.email`,
+ `});`,
+ ``,
+ `const mapDispatchToProps = (dispatch) => ({`,
+ ` updateUser: (userData) => dispatch({ type: 'UPDATE_USER', payload: userData })`,
+ `});`,
+ ``,
+ `export default connect(mapStateToProps, mapDispatchToProps)(UserData);`,
+ ]}
+ language="jsx"
+ />
+
+ ),
+ },
+ {
+ title: 'Redux (2015~현재)',
+ content: (
+
+
+ 의 철학
+
+
+ - 중앙에서 상태를 관리한다
+ - 상태를 변경하는 방법은 action 을 dispatch 하는 것 뿐
+ - 상태를 변경하는 로직은 reducer 에서 처리
+ - 상태를 조회하는 로직은 selector 에서 처리
+ - 이 과정에서 불필요한 리렌더가 없게 해서 성능을 최적화
+
+
+
state.user);`,
+ ` const dispatch = useDispatch();`,
+ ``,
+ ` return (`,
+ ` `,
+ `
User Data
`,
+ `
Username: {username}
`,
+ `
Email: {email}
`,
+ `
`,
+ `
`,
+ ` );`,
+ `}`,
+ ]}
+ language="jsx"
+ />
+
+ 하지만 여러 문제점들도 있었는데,
+
+ -
+ 너무 큰 보일러플레이트 코드 (상태 하나 만드는데에 짜야 할
+ 코드가 너무 많다)
+
+ -
+ ...뭐라뭐라 하던데 사실 별로 공감은 안 됐습니다. 아무튼
+ hater가 많아요
+
+
+
+ ),
+ },
+ {
+ title: 'Recoil (2020~현재)',
+ content: (
+
+
+ 의 철학
+
+
+
+
얘는 또 다른 문제가 있는데,
+
+ - 1버전이 계속 안 나오더니 결국 페이스북에서 버렸음
+
+
+ ),
+ },
+ {
+ title: '그리고 다른 상태관리 라이브러리들',
+ content: (
+
+
+ 한때 , {' '}
+ 과 함께 삼대장이었던
+
+
+
+ 가 발전한{' '}
+
+
+
+ 를 개선한{' '}
+
+
+
+ 을 개선한{' '}
+
+
+
+ 벨로퍼트님이 만드신
+
+
..등등
+
+ ),
+ },
+ {
+ title: '그리고 게임 체인저: tanstack query (2020~)',
+ content: (
+
+
+
+
+
+
+ 맞는 말입니다. 기존의 를 그냥
+ 좀더 이쁘게 감싸놓은 수준인 상태관리 도구들은 서버에서 받아온
+ 데이터를 관리하는 문제를 잘 풀지 못했습니다.
+
+
캐싱, 로딩, 폴링 등
+
+ 그래서 는 이런 데이터를{' '}
+ 서버 상태 라고 정의하고,{' '}
+ 서버 상태 관리 도구라고 자신을 소개합니다.
+
+
+
+ ),
+ },
+ {
+ title: '그리고 게임 체인저: tanstack query (2020~)',
+ content: (
+
+
{`,
+ ` const { data, isLoading, error, refetch } = useQuery({`,
+ ` queryKey: ['userData'],`,
+ ` queryFn: fetchUserData,`,
+ ` });`,
+ ``,
+ ` if (isLoading) return Loading...
;`,
+ ` if (error) return An error occurred: {error.message}
;`,
+ ``,
+ ` return (`,
+ ` `,
+ `
User Data
`,
+ `
Username: {data.username}
`,
+ `
Email: {data.email}
`,
+ `
`,
+ ` );`,
+ `}`,
+ ]}
+ language="jsx"
+ />
+
+ 이런 식으로, 서버에서 데이터를 가져오는 것을 훨씬 편하게 해
+ 줬습니다.
+
+
+ 캐싱, 재시도, 무효화 등 서버 데이터를 다루는 데 필수인 기능들도
+ 물론 제공합니다.
+
+
+ 비슷한 철학을 가진 이라는
+ 라이브러리도 있습니다.
+
+
+ ),
+ },
+ {
+ title: '그래서 지금은 뭐가 가장 핫한가요?',
+ content: (
+
+
자료를 만드는 2024년 9월 16일 기준으로,
+
+ 클라이언트 상태관리 - 서버상태관리를 나누는 철학은 일반적인
+ 컨셉이 되었습니다.
+
+
+ 클라이언트 상태관리 도구는 사용하지 않거나{' '}
+ 중에
+ 취향껏 쓰고, 서버 상태 관리 도구는{' '}
+ 를 쓰는 게 일반적입니다.
+
+
+ 제 취향은 하나만 쓰고
+ 클라이언트 상태관리는 모두
+ 로 처리하는 것인데, 프로젝트
+ 성격에 따라 다르긴 합니다
+
+
+ ),
+ },
+ ]}
+ />
+ ),
});
diff --git a/frontend/lecture/src/lectures/Styling/index.tsx b/frontend/lecture/src/lectures/Styling/index.tsx
index b0b9d0c..f33b76d 100644
--- a/frontend/lecture/src/lectures/Styling/index.tsx
+++ b/frontend/lecture/src/lectures/Styling/index.tsx
@@ -4,6 +4,7 @@ import { CodeSnippet } from '@/components/CodeSnippet';
import { ExternalLink } from '@/components/ExternalLink';
import { InlineCode } from '@/components/InlineCode';
import { Slides } from '@/components/Slides';
+import { StackBadge } from '@/components/StackBadge';
import { getLectureItem } from '@/lectures';
import cssIsAwesome from './cssisawesome.gif';
@@ -45,7 +46,7 @@ export const stylingLecture = getLectureItem({
content: (
- CSS (Cascading Style Sheets)
+ (Cascading Style Sheets)
브라우저 DOM 요소들에 스타일을 먹이는 언어
@@ -190,7 +191,10 @@ export const stylingLecture = getLectureItem({
title: 'CSS 생산성 - CSS in JS (2014~)',
content: (
-
styled-components, emotion 등 라이브러리를 사용
+
+ ,{' '}
+ 등 라이브러리를 사용
+
취향에 맞는 걸 잘 찾아서 사용하자!
- 저는 Tailwind 를 가장 선호합니다
+ 저는
를 가장 선호합니다
왜 Tailwind 가 제일 괜찮은지 30분 정도 떠들 수 있긴 한데
diff --git a/frontend/lecture/src/lectures/WrapUp/index.tsx b/frontend/lecture/src/lectures/WrapUp/index.tsx
new file mode 100644
index 0000000..c2ffff6
--- /dev/null
+++ b/frontend/lecture/src/lectures/WrapUp/index.tsx
@@ -0,0 +1,9 @@
+import { Slides } from '@/components/Slides';
+import { getLectureItem } from '@/lectures';
+
+export const wrapupLecture = getLectureItem({
+ title: '마무리',
+ description: '',
+ date: new Date('2024-11-20 20:30:00'),
+ element: ,
+});
diff --git a/frontend/lecture/src/pages.tsx b/frontend/lecture/src/pages.tsx
index 89eeadc..79a9414 100644
--- a/frontend/lecture/src/pages.tsx
+++ b/frontend/lecture/src/pages.tsx
@@ -11,6 +11,7 @@ import { architectureLecture } from '@/lectures/Architecture';
import { asyncLecture } from '@/lectures/Async/lecture';
import { dataFetchingLecture } from '@/lectures/DataFetching/lecture';
import { environmentLecture } from '@/lectures/Environment';
+import { futureLecture } from '@/lectures/Future';
import { infrastructureLecture } from '@/lectures/Infrastructure';
import { initializeProjectLecture } from '@/lectures/InitializeProject';
import { otLecture } from '@/lectures/OT';
@@ -21,6 +22,7 @@ import { stateManagementLecture } from '@/lectures/StateManagement';
import { stylingLecture } from '@/lectures/Styling';
import { typescriptLecture } from '@/lectures/TypeScript';
import { webBasicLecture } from '@/lectures/WebBasic/lecture';
+import { wrapupLecture } from '@/lectures/WrapUp';
import { Home } from '@/pages/home';
export const pages: (
@@ -56,22 +58,8 @@ export const pages: (
{ path: '/state-management', ...stateManagementLecture },
{ path: '/performance', ...performanceLecture },
{ path: '/infrastructure', ...infrastructureLecture },
- {
- type: 'lecture',
- title: '생태계',
- description: 'Next.js',
- date: new Date('2024-11-20 20:30:00'),
- path: '/meta-framework',
- element: TBD
,
- },
- {
- type: 'lecture',
- title: '마무리',
- description: '',
- date: new Date('2024-11-20 20:30:00'),
- path: '/end',
- element: TBD
,
- },
+ { path: '/future', ...futureLecture },
+ { path: '/wrapup', ...wrapupLecture },
{
path: '/como-0',
...getComoAssignment({ seminar: 0, due: new Date('2024-09-10 23:59:59') }),