generated from muhandojeon/study-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f081052
commit d7876c0
Showing
2 changed files
with
216 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
# 자바스크립트 MV* 패턴 | ||
|
||
## 8.1 MVC 패턴 | ||
|
||
### M 모델 | ||
|
||
모델은 애플리케이션의 데이터를 관리 | ||
|
||
모델이 변경되었을 때 뷰에 변경사항을 알려주는 역할을 한다. | ||
|
||
> 뷰는 모델에 직접적으로 접근하지 않는다. | ||
### V 뷰 | ||
|
||
뷰는 모델에 대한 시각적인 표현 | ||
|
||
### C 컨트롤러 | ||
|
||
모델과 뷰를 연결하는 역할 | ||
|
||
모델과 뷰 사이의 중재자 역할을 한다. | ||
|
||
|
||
#### 만약 리액트에서 구현한다면? | ||
|
||
```tsx | ||
const userAPI = { | ||
getUser: async (id: number): Promise<User> => { | ||
return { id, name: "John", email: "john@example.com" }; | ||
}, | ||
updateUser: async (id: number, name: string): Promise<User> => { | ||
return { id, name, email: "john@example.com" }; | ||
} | ||
}; | ||
|
||
class UserModelMVC { | ||
private user: User | null = null; | ||
private listeners: Set<() => void> = new Set(); | ||
|
||
subscribe(listener: () => void) { | ||
this.listeners.add(listener); | ||
return () => this.listeners.delete(listener); | ||
} | ||
|
||
private notify() { | ||
this.listeners.forEach(listener => listener()); | ||
} | ||
|
||
async fetchUser(id: number) { | ||
this.user = await userAPI.getUser(id); | ||
this.notify(); | ||
} | ||
|
||
async updateName(name: string) { | ||
if (this.user) { | ||
this.user = await userAPI.updateUser(this.user.id, name); | ||
this.notify(); | ||
} | ||
} | ||
|
||
getUser() { return this.user; } | ||
} | ||
|
||
// MVC View | ||
const UserViewMVC = () => { | ||
const [user, setUser] = useState<User | null>(null); | ||
const model = useMemo(() => new UserModelMVC(), []); | ||
|
||
useEffect(() => { | ||
const unsubscribe = model.subscribe(() => { | ||
setUser(model.getUser()); | ||
}); | ||
model.fetchUser(1); | ||
return unsubscribe; | ||
}, [model]); | ||
|
||
if (!user) return <div>Loading...</div>; | ||
|
||
return ( | ||
<div> | ||
<h2>MVC Pattern</h2> | ||
<input | ||
value={user.name} | ||
onChange={e => model.updateName(e.target.value)} | ||
/> | ||
<div>{user.email}</div> | ||
</div> | ||
); | ||
}; | ||
``` | ||
|
||
이렇게 되지 않을까? | ||
|
||
### 8.6 MVP 패턴 | ||
|
||
### M 모델 | ||
|
||
동일 | ||
|
||
### V 뷰 | ||
|
||
동일 | ||
|
||
### P 프레젠터 | ||
|
||
모델과 뷰를 연결하는 역할, 뷰에서 이벤트 호출은 프레젠터에서 처리 | ||
|
||
#### 만약 리액트에서 구현한다면? | ||
|
||
```tsx | ||
class UserModelMVP { | ||
private user: User | null = null; | ||
|
||
async fetchUser(id: number) { | ||
this.user = await userAPI.getUser(id); | ||
return this.user; | ||
} | ||
|
||
async updateName(name: string) { | ||
if (this.user) { | ||
this.user = await userAPI.updateUser(this.user.id, name); | ||
return this.user; | ||
} | ||
return null; | ||
} | ||
} | ||
|
||
class UserPresenter { | ||
constructor( | ||
private model: UserModelMVP, | ||
private setUser: (user: User) => void | ||
) {} | ||
|
||
async loadUser(id: number) { | ||
const user = await this.model.fetchUser(id); | ||
if (user) this.setUser(user); | ||
} | ||
|
||
async updateName(name: string) { | ||
const user = await this.model.updateName(name); | ||
if (user) this.setUser(user); | ||
} | ||
} | ||
|
||
// MVP View | ||
const UserViewMVP = () => { | ||
const [user, setUser] = useState<User | null>(null); | ||
const presenterRef = useRef<UserPresenter>(); | ||
|
||
useEffect(() => { | ||
const model = new UserModelMVP(); | ||
presenterRef.current = new UserPresenter(model, setUser); | ||
presenterRef.current.loadUser(1); | ||
}, []); | ||
|
||
if (!user) return <div>Loading...</div>; | ||
|
||
return ( | ||
<div> | ||
<h2>MVP Pattern</h2> | ||
<input | ||
value={user.name} | ||
onChange={e => presenterRef.current?.updateName(e.target.value)} | ||
/> | ||
<div>{user.email}</div> | ||
</div> | ||
); | ||
}; | ||
``` | ||
|
||
### 중간 정리 | ||
|
||
MVC, MVP 너무 비슷하다라는 느낌을 받았고, 실제 코드를 작성할 때도 뭔가 명확하게 나누기 어렵지 않나 라는 생각이 들었다. | ||
|
||
## 8.8 MVVM 패턴 | ||
|
||
되게 이해가 잘 안되어서 claude 녀석의 답변을 첨부합니다,, | ||
|
||
MVVM은 간단히 말해서 "데이터의 자동 동기화"가 핵심입니다. 실생활에서 은행 ATM을 예로 들어보겠습니다: | ||
|
||
Model (통장): 실제 계좌의 잔액 정보를 가지고 있음 | ||
ViewModel (은행 직원): 통장의 정보를 화면에 표시할 수 있는 형태로 변환하고 관리 | ||
View (ATM 화면): 사용자에게 정보를 보여주고 입력받음 | ||
|
||
여기서 ViewModel(은행 직원)은: | ||
|
||
Model(통장)의 잔액이 변경되면 자동으로 View(화면)에 반영 | ||
사용자가 View(화면)에서 입력한 내용을 Model(통장)에 반영 | ||
필요한 경우 데이터 형식을 변환 (예: 숫자 → 통화 형식) | ||
|
||
> 이게 맞는 것인지 이따가 여러분들 의견좀 듣겠습니다,, | ||
## 8.10 MV* 패턴과 리액트 | ||
|
||
> 되게 이해가 안 가는게 P.201_L4) MVC로 분류되지 않습니다, ... P.202_L2) 전통적인 MVC 형태로 동작합니다. <- 이게 대체 뭔말인지 .,,, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# 9 비동기 프로그래밍 패턴 | ||
|
||
자주 놓칠 수 있는 부분인 것만 작성하겠습니다 , , | ||
|
||
## 9.3 프로미스 패턴 | ||
|
||
### 9.3.3 프로미스 병렬 처리 | ||
|
||
사실 프론트엔드에서 사용할 일이 자주 있진 않은데, 백엔드 코드 작성할 땐 종종 있는 것 같아서요.\ | ||
혹은 SSR할 때?,., | ||
|
||
여튼 다들 아시겠지만 Promise.all 을 사용하면 병렬처리가 되는데 깜빡할 수도 있으니 , , | ||
|
||
### 9.3.7 프로미스 재시도 | ||
|
||
요것도 auth 처리할 때 자주 사용하는 것 같네요! | ||
|
||
## 궁금한 것 | ||
|
||
- 여러분들은 9.4.3 비동기 에러 처리할 때 어떤 방식으로 하시나요? | ||
- 책에 보여진 패턴(메서드) 중 어떤 것들을 사용해 보셨나요? ex) race, allSettled, any, withResolvers 등등,, |