๋ฐ๋ ค๊ฒฌ MBTI ๊ฒ์ฌ๋ฅผ ํตํ ์ปค๋ฎค๋ํฐ ์น ์๋น์ค
๐ ์ฌ์ดํธ : https://withdog.me/
๐ ์ ํ๋ธ
1๋ถ - ๋ฉ์ธ & ํ์๊ฐ์ , ๋ก๊ทธ์ธ & MBTI๊ฒ์ฌ
2๋ถ - ๐ ์ฑํ โ
3๋ถ - ๊ฒ์๊ธ ์์ฑ
โจ ํ๋ก์ ํธ ๋ค์ด๊ฐ๊ธฐ ๐ (1) ์์ฒด ํ๋ก์ ํธ with-dog UI
โจ ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ ๐ (2) ์์ฒด ํ๋ก์ ํธ with-dog ์ฑํ ๊ตฌํ
ํ๋ก์ ํธ ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ์ ์์ Websocket๊ณผ Socket.IO ๊ฐ๋ ์๊ณ ์ตํ๊ธฐ. ์ค์ต ํ๋ก์ ํธ !
1. JavaScript + Websocket ๐ WebSocket ์ผ๋ก ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ ํด๋ณด๊ธฐ
2. JavaScript + Socket.IO & React + Socket.IO ๐ Socket.IO๋ก ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ ํด๋ณด๊ธฐ
ํ๋ก์ ํธ ๊ธฐ๊ฐ
22.08 ~ 22.09
๊ฐ๋ฐ ์ธ์
Front-end 5๋ช
, Back-end 1๋ช
ํ์ ๊ตฌํ
Nav, ๋ฉ์ธ ํ์ด์ง
๋ก๊ทธ์ธ (์์
๋ก๊ทธ์ธ) & ํ์๊ฐ์
๊ฒ์ํ (๋ฉ์ธ, ๊ธ์์ฑ, ๋ํ
์ผ)
MBTI (๊ฒ์ฌ, ๊ฒฐ๊ณผ)
์ฑํ
๋ฐฉ (๋ฆฌ์คํธ, ์ฑํ
๋ฐฉ) โ๏ธ
๋ง์ดํ์ด์ง
๊ด๋ฆฌ์ ํ์ด์ง
์ถ๊ฐ ๊ตฌํ
์ฐ์ฑ
์์คํ
๐ focus
3์ฐจ ํ๋ก์ ํธ๋ ์๋ ๋ด์ฉ๋ค์ ๋ชฉํ๋ก ์งํ๋์๋ค.
Front-end
: HTML/CSS, JavaScript, React, React-Router, React-Redux, TypeScript, Socket.IO, Styled-Component, AWS(EC2)
Back-end
: Python, Django web framework, Django Ninja, Postgresql, python-socketio , MongoDB(pymongo) / AWS S3, RDS, EC2, NGINX, Heroku, MongoDB Cloud, Gunicorn and Eventlet worker
GitHub, Slack, Notion
๐ yarn ๋์ ์ npm์ฌ์ฉํ๊ธฐ.
๐ ๋จ์, Naming, Type Appointment, CSS ์์ฑ ์์, Commit Role, , UI ๊ตฌ์ฑ ํฌ๊ธฐ, React import ์ปจ๋ฒค์
์ง์
๐ ์ค์นํ์ผ ๋ด์ฉ
// ๋ฆฌ์กํธ, ํ์
์คํฌ๋ฆฝํธ, ๋ฆฌ์กํธ ๋ผ์ฐํฐ๋ ์ค์น
npx create-react-app with-dog โtemplate typescript
npm install react-router-dom --save
// ํ์
์คํฌ๋ฆฝํธ์ ๋ฆฌ์กํธ, ๋ฆฌ์กํธ ๋ผ์ฐํฐ๋, ๋ฆฌ์กํธ ๋
// ๋ง์ฝ package.json์ types/react, react-dom์ด ์ค์น๋์ด ์๋์ง ํ์ธํ ๊ฒ(์ค๋ฅ ๋ฐ์ ์์ธ)
npm install โsave @types/react,react-dom,react-router-dom
// ํ์
์คํ์ผ๋ ์ปดํฌ๋ํธ ์ค์น
npm install โsave @types/styled-components
// TypeScript์์ eslint, prettier ์ฌ์ฉํ๊ธฐ ์ํ ์ค์น ์์
npm i -D typescript eslint prettier
npm i -D @typescript-eslint/eslint-plugin @typescript-eslint/parser # ํ์
์คํฌ๋ฆฝํธ ํ๋ฌ๊ทธ์ธ
npm i -D eslint-config-prettier eslint-plugin-prettier # prettier ํ๋ฌ๊ทธ์ธ
// react ํ๊ฒฝ์์์ react + redux ์ค์น
npm i redux react-redux
// react + typescript ํ๊ฒฝ์์์ react + redux ์ค์น
npm i --dev @types/react-redux
// axios ์ค์น
npm install axios
๐ ๋๋ ํ ๋ฆฌ, ํ์ผ ๊ตฌ์กฐ ์ธํ
with_dog
โโโ package-lock.json
โโโ package.json
โโโ public
โ โโโ images
โ โ โโโ dog1.jpg - ์์ ์ด๋ฏธ์ง ํ์ผ ์ถ๊ฐ
โ โโโ index.html
โโโ src
โ โโโ Router.tsx
โ โโโ config.ts
โ โโโ index.tsx
โ โโโ pages
โ โ โโโ Admin
โ โ โ โโโ Admin.tsx
โ โ โโโ Chatting
โ โ โ โโโ Chatting.tsx
โ โ โโโ Login
โ โ โ โโโ Login.tsx
โ โ โ โโโ SignIn
โ โ โ โ โโโ SignIn.tsx
โ โ โ โโโ Signup
โ โ โ โโโ Signup.tsx
โ โ โโโ MBTI
โ โ โ โโโ MBTI.tsx
โ โ โโโ Main
โ โ โ โโโ Main.tsx
โ โ โโโ MainRouter
โ โ โ โโโ MainRouter.tsx
โ โ โโโ Mypage
โ โ โ โโโ Mypage.tsx
โ โ โโโ NoticeBoard
โ โ โ โโโ NoticeBoard.tsx
โ โ โโโ components
โ โ โโโ Footer
โ โ โ โโโ Footer.tsx
โ โ โโโ Nav
โ โ โโโ Nav.tsx
โ โโโ styles
โ โโโ GlobalStyles.tsx
โ โโโ Theme.tsx
โโโ tsconfig.json - "baseUrl": "./src" ์ฝ๋ ์ถ๊ฐ
1) Router.tsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Signup from './pages/Login/Signup/Signup';
import MainRouter from './pages/MainRouter/MainRouter';
const Router = () => {
return (
<BrowserRouter>
<Routes>
<Route path="/signup" element={<Signup />} />
<Route path="/*" element={<MainRouter />} />
</Routes>
</BrowserRouter>
);
};
export default Router;
2) MainRouter.tsx
Nav
, Footer
์ ์ฉ ๋ชฉ์ 3) config.ts
export const BASE_URL = 'http://...';
const API = {
signUp: `${BASE_URL}/users/signup`,
signIn: `${BASE_URL}/users/login`,
...
};
export default API;
4) index.tsx
5) GlobalStyles.tsx
6) Theme.tsx
7) eslintsrc
8) prettierrc
9) tsconfig.json baseUrl ์ถ๊ฐ โ "baseUrl": "./src"
10) j. srcํด๋์ types ํด๋ ๋ง๋ค๊ณ svg.d.ts ํ์ผ ์ถ๊ฐ
declare module '*.svg' {
const value: React.DetailedHTMLProps<
ImgHTMLAttributes<HTMLImageElement>,
HTMLImageElement
>;
export default value;
}
์ฑํ ๋ฆฌ์คํธ ํ์ด์ง UI ๊ตฌํ
props์ type / intrinsicattributes ํ์์๋ฌ์ interface props
โ 'intrinsicattributes' ํ์์ ํ ๋นํ ์ ์์ต๋๋ค. ์ด์ ํด๊ฒฐํ๊ธฐ!
title={title}
์ ๋ฐ์ค, ์์๊ฐ์ ์๋ฌ๋ฌธ๊ตฌ๊ฐ ๋ด๋ค.const Chatting = () => {
return (
<ChattingContainer>
{CHATLIST_DATA.map(({ id, title, description }) => {
return <ChatList key={id} title={title} description={description} />;
})}
</ChattingContainer>
);
};
โ๏ธ๋จ์ํ ํ์ ์ปดํฌ๋ํธ์์ props๋ฅผ ์ ๋ฌ๋ฐ์ ๊ตฌ์กฐ๋ก ์ธํ ํด์ฃผ๋ฉด ํด๊ฒฐ๋์๋ค.
const ChatList = ({ title, description }: ChatListProp) => { // ์ด๋ถ๋ถ
return (
<ChatListContainer>
<ChatListLeft title={title} description={description} />
<ChatListRight />
</ChatListContainer>
);
};
๋จ ์ฌ๊ธฐ์ props๋ก ๋ฐ์์ฌ ์์์ ํ์ ์ค์ ์ ํด์ฃผ์ด์ผ ํ๋ค!
export interface ChatListProp {
id?: number;
title: string;
description: string;
}
type โ number | undefined
โ ModalHandler์์ id๋ฅผ ๋ฐ์์ฌ๋ ์์ ๊ฐ์ ์ค๋ฅ๊ฐ ๋ฌ๋ค.
โ๏ธ ์๋์ ๊ฐ์ด ํ์์ ์ถ๊ฐ๋ก ๊ธฐ์ฌํด ์ฃผ์๋ค.
const ChatListRight = ({ id }: ChatListProp) => {
const ModalHandler = (id: number | undefined) => { // ์ด๋ ๊ฒ ์ถ๊ฐ๋ก ๊ธฐ์ฌํจ
console.log(id);
};
return (
<GoChatRightContainer
onClick={() => {
ModalHandler(id);
}}
>
<GoChatIntro> ์ดํด๋ณด๊ฐ </GoChatIntro>
<GoChatIntroIcon src={ArrowRight} />
</GoChatRightContainer>
);
};
์ฌ๋ฌ๊ฐ์ svg ํ์ผ ๊ฐ์ ธ์์ map ๋ฉ์๋๋ก ๋๋ฆฌ๊ธฐ / type ์ง์
1) svg ํ์ผ์ import ํด์ค๊ธฐ
import { ReactComponent as Icon1 } from 'assets/svg/ํํ๊ฐํ.svg';
import { ReactComponent as Icon2 } from 'assets/svg/์ ๋ต๊ฐํ.svg';
import { ReactComponent as Icon3 } from 'assets/svg/๊พธ๋ฌ๊ธฐํ.svg';
import { ReactComponent as Icon4 } from 'assets/svg/ํ๋๊ฐํ.svg';
2) map์ ๋ฐ์ดํฐ๋ฅผ ๋๊ธฐ๊ธฐ ์ํ ์์ ๋ฐ์ดํฐ ์์ฑ
{
id: 1,
Image: Icon1,
title: 'ํํ๊ฐ',
description:
'์์ฌํ์ง๋ง ์ธ์์ด ๊ถ๊ธํ ๋๋์ด, ์ธค๋ฐ๋ ๋๋์ด, ๋ชฝ์์ ์ฆ๊ธฐ๋ ํํ์ ๋๋์ด๋ค์ ์ํ ์ฑํ
๋ฐฉ์
๋๋ค!',
},
3) type ์ค์ ์ ํด์ฃผ๊ธฐ
export interface ChatListProp {
id?: number;
Image?: any;
title: string;
description: string;
}
// any ํ์
์ด ์๋ ์ง์ ์ ํด์ฃผ๊ณ ์ถ์๋๋ฐ ์์ง ํด๊ฒฐ๋ฐฉ๋ฒ์ ์ฐพ์ง ๋ชปํ๋ค.
4) Image ์ปดํฌ๋ํธ๋ก ๋๋ฆฌ๊ธฐ
const ChatListLeft = ({ Image, title, description }: ChatListProp) => {
return (
<ChatListLeftContainer>
<Image />
<DogType>{title}</DogType>
<Introduce>{description}</Introduce>
</ChatListLeftContainer>
);
};
5) style ์์ฑ ์ง์ ํ๊ธฐ
<Image style={{ width: '100px', marginRight: '16px' }} />
ํ์ ์ง์ ํ๊ธฐ
declare module '*.svg' {
import React = require('react');
export const ReactComponent: React.FC<React.SVGProps<SVGSVGElement>>;
const src: string;
export default src;
}
export interface ChatListProp {
id?: number;
Image?: any;
title: string;
description: string;
}
โ any
๋ถ๋ถ์ React.FC<React.SVGProps<SVGSVGElement>>
๋ฅผ ์ง์ ํ๋ฉด ์์์ปดํฌ๋ํธ์์๋ ์๋ฌ๊ฐ ๋จ์ง ์์์ง๋ง ํด๋น ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋ ๋ถ๋ถ์์ ts(2604)์๋ฌ๊ฐ ๋ด๋ค. ๐ฅฒ
์ฑํ ๋ฆฌ์คํธ ํ์ด์ง ๋ชจ๋ฌ UI ๊ตฌํ
CHATLIST_DATA ์์๋ฐ์ดํฐ ๋ถ๋ฆฌ
์ฑํ ๋ฆฌ์คํธ ํ์ด์ง์ ๋ค์ด๊ฐ๋ ๋ฐ์ดํฐ + ๋ชจ๋ฌ์ ๋ค์ด๊ฐ๋ ๋ฐ์ดํฐ ๋ฅผ ๋ฌถ์ด์ ์์๋ฐ์ดํฐ๋ก ๋ง๋ค๊ณ ๋ฐ๋ก DATA ํด๋๋ก ๊ด๋ฆฌํ๋ค.
๋ชจ๋ฌ ์ค์๋ฐฐ์น
position
์์ฑ๊ณผ top
, transform
์์ฑ์ ํตํด์ ์ค์์ผ๋ก ๋ฐฐ์นํ๋ค.โจ
const ChatModalContainer = styled.div`
${props => props.theme.flex.flexBox('column')}
position: fixed;
top: 50%;
width: 30rem;
height: 40rem;
transform: translateY(-49%);
background-color: white;
box-shadow: 1px 1px 15px 2px rgba(0, 0, 0, 0.1);
border-radius: 1.2rem;
z-index: 2;
`;
๋ชจ๋ฌ show์ํ ๋ฐ ํ ๊ธ ํจ์๋ก ํธ๋ค๋งํ๊ธฐ
isShowModal
์ํ๋ฅผ ์ถ๊ฐํด์ ํด๋ฆญ์ ํ ๊ธํจ์๋ฅผ ํตํด false or true ์ํ๋ฅผ ํธ๋ค๋งํ๋๋ก ์์ฑํ๋ค.<BackGround onClick={onClickToggleModal} />
๋ชจ๋ฌ์ ํ ๊ธ ํจ์๋ฅผ ์ ๋ฌํด์ ๋ฐฑ๊ทธ๋ผ์ด๋ ํด๋ฆญ์ ํ ๊ธํจ์๋ฅผ ํตํด isShowModal
์ํ๋ฅผ false๋ก ์ค์ ํจ์ผ๋ก์จ ๋ชจ๋ฌ ๋ณด์ด๊ธฐ ๋ซ๊ธฐ๋ฅผ ๊ตฌํํ๋ค.โ๏ธ Redux ๋ฒจ๋ก๊ทธ ์ ๋ฆฌ (Action, Reducer, Store, CombineReducers)
๐ ์ํ๊ด๋ฆฌ
๋ฆฌ๋์ค๋ฅผ ์ฌ์ฉํ๋ฉด์ ๊ถ๊ธํ๋ ์ ์๋ํด ํ์ ์ ๊ณ์ ๋ถ๊ป ์ฌ์ญค๋ณด์๋ค. ๐ง โ๏ธ
Q.
๋ฐฑ์ด๋ ํต์ ์๋ ํ๋ก ํธ์์ ํ์ํ ์์๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ ์์ ์ด๋ค. ๊ทธ๋ฐ๋ฐ ์ต์์ ๋ถ๋ชจ ์ปดํฌ๋ํธ์์ map์ ๋๋ ค์ ์ฐ์ด๋ด๋ ํํ๋ผ์ ํ๋กญ์ค ๋๋ฆด๋ง์ด ๊ณ์ ๋ค์ด๊ฐ๋ค. ์ด ๊ฒฝ์ฐ ๋ฆฌ๋์ค๋ฅผ ์ฐ๋ฉด ์ ์ญ๋ฐ์ดํฐ๋ฅผ ์๋ฌด๋ฐ์๋ ๋ฝ์์ค๋ฉด ๋๋๊น ๋๋ฆด๋ง์ ์ํด๋ ๋ ๊ฒ์ด๋ผ๊ณ ์์ํ๋ค.
ํ์ง๋ง ์๊ฐํด๋ณด๋ ๋งต์ ๋๋ฆฌ๊ณ ํ์ํ ์์ ๋ฐ์ดํฐ๋ฅผ ๋ด๋ ค์ฃผ๋๊ฒ ๋ง๋๊ฑฐ ๊ฐ์ผ๋ ๋ฆฌ๋์ค๋ฅผ ๊ผญ ์จ์ผํ ์ง ์๋ฌธ์ด๋ค.
A.
๊ธฐ๋ณธ์ ์ผ๋ก ๋ฐ๋ก ํ์๋ก ๋ด๋ ค์ค๋ค๊ฑฐ๋ ๋๋ฆด๋ง์ด ์ฌํ์ง ์์ผ๋ฉด ๋ฆฌ๋์ค๋ฅผ ์์ฐ๊ณ ํ๋กญ์ค๋ก ๋ด๋ ค์ค๋ค. ๊ทธ๊ฒ ๋ ๊ด๋ฆฌํ๊ธฐ๋ ์ฝ๊ณ ์์ ๋ณด๊ธฐ๋ ์ฝ๊ณ ์ง์ง ๋๋ฆด๋ง์ผ๋ก ์ธํด ์ธ๋ฐ ์๋ ์ปดํฌ๋ํธ๋ ๋ฌด๋ถ๋ณํ๊ฒ ๊ฑฐ์ณ๊ฐ๊ฑฐ๋ ์ํ๊ด๊ณ์์์ ๋ฐ์ดํฐ ์ ๋ฌ, ์ปดํฌ๋ํธ๊ฐ ์ฐ๊ฒฐ๋์ด์์ง ์์ ๊ณณ์ผ๋ก์ ๋ฐ์ดํฐ ์ ๋ฌ ์์ ๋ณดํต ์ฐ์ธ๋ค.
๊ทธ๋ฆฌ๊ณ ๋ฆฌ๋์ค๋ก ๊ฐ์ ธ์จ store ๋ฐ์ดํฐ๋ฅผ map์ ๋๋ฆด์ ์๋ ์๋๋ฅผ ๋ฌผ์ด๋ณธ๋ค๋ฉด ๋๋ ค๋ ์๊ด ์๋ค. ์์ ๊ฐ์ ์ํฉ์์ api์์ ๋ฐ์์จ ๊ฐ์ฒด๋ฅผ ๋๋ฆด๋ ๋ณดํต ๊ทธ๋ ๊ฒ ํ๋ค. ( ๋น๋๊ธฐapi->๋ฏธ๋ค์จ์ด->๋ฆฌ๋์ค->store ๊ฐ์ ธ์์ map )
Q.
๋ง์ฝ ํ์์๋ ์ปดํฌ๋ํธ์์ ๋๋ฆด๋ง์ด 1~2๋ฒ ์ ๋ ๋ฐ์ํ ๊ฒฝ์ฐ ๋ฆฌ๋์ค๋ก ๋นผ๋์ง? ์ฆ, ์ํ๊ด๋ฆฌ๋ฅผ ํ๋ ์ฝ๋๊ฐ ์๋๋ผ ์ผ๋ฐ์ ์ธ ์์๋ฐ์ดํฐ๋ Store๋ก ๊ด๋ฆฌํ๋์ง? (ํ์ฌ Data ํด๋๋ฅผ ๋ฐ๋ก ๋ง๋ค์ด์ ์์๋ฐ์ดํฐ ๋ด์์ ๊ด๋ฆฌ์ค)
A.
๋ณดํต์ ์ง์ง ํ์ํ ๊ณณ์์๋ง ์ด๋ค. ์์๋ ๋ณดํต ์ํ๋๊ฑฐ ๊ฐ๊ณ ์์๋ ๋ง๊ทธ๋๋ก ์จ์ผ ๋๋๊ณณ์์๋ง ๋ฐ๋ก ๋ง๋ค์ด์ ์ฐ๋๊น ์คํ ์ด ๋ง์ด ๋ง๋ค๊ณ ํ์์๋๊ณณ๊น์ง ๋ฌด๋ถ๋ณํ๊ฒ ์ฐ๋ฉด ๊ทธ๊ฑฐ๋ง์ ๋ ๋ฆฌ์์ค ๋ญ๋น๋ผ์ ์ฐ๋ฆฌ๋ ๊ตณ์ด ์๋ฃ์ ๋ณ๋์ด ์๋ ๊ฒ๋ค์ ์์๋ก ๋ง๋ค์ด์ data์ ๋ฃ๊ณ ์ฐ๊ณ ์๋ค.
์ํ๊ด๋ฆฌ๋ ์ง์ง ํ์ํ๊ณณ, ์๋ฅผ ๋ค๋ฉด ๋ชจ๋ ์ปดํฌ๋ํธ์์ ๊ฐํธํ๊ฒ ๋ค ๊ฐ์ ธ๋ค ์จ์ผํ๋๊ฒ, ๋ก๊ทธ์ธ, ์ธ์ฆ์ธ๊ฐ, ํ ํฐ ๋คํฌ๋ชจ๋.. ๊ฒ์ํ ๊ด๋ จ ๋ฑ๋ฑ / ๋จ์ ๋๋ฆด๋ง์ ํผํ๊ธฐ ์ํด ์ฐ์ง ์๋๋ค.
Q.
๋ฆฌ๋์ค์ ์ปจํ
์คํธ๋ฅผ ๋์์ ์ฐ๊ธฐ๋ ํ๋์ง?
A.
์ํ๊ด๋ฆฌ๋ ํ๋๋ก ํต์ผํด์ ์จ์ผ์ง ๊ทธ๋ ๊ฒ ๋๋ฉด ๊ด๋ฆฌํ๊ธฐ๋ ์ฝ์ง ์๊ณ ์ปจํ
์คํธ์ ๋ชจ๋ ๊ธฐ๋ฅ์ด ๋ฆฌ๋์ค์ ์๊ณ ์ฑ๋ฅ๋ ๋ฆฌ๋์ค๊ฐ ์ข๋ค.
ํ๋ก์ ํธ ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ์ ์์ Websocket๊ณผ Socket.IO ๊ฐ๋ ์๊ณ ์ตํ๊ธฐ. ์ค์ต ํ๋ก์ ํธ !
1. JavaScript + Websocket ๐ WebSocket ์ผ๋ก ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ ํด๋ณด๊ธฐ
2. JavaScript + Socket.IO ๐ Socket.IO๋ก ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ ํด๋ณด๊ธฐ
3. React + Socket.IO ๐ Socket.IO๋ก ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ ํด๋ณด๊ธฐ
โจ with-dog ํ๋ก์ ํธ ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ ๐ โจโจ์ฐ๋ฆฌ ํ๋ก์ ํธ์ ์ฑํ ๊ธฐ๋ฅ ๊ตฌํํ๊ธฐโจโจ