diff --git "a/\354\261\225\355\204\260_8/\354\204\234\354\244\200\355\231\230.md" "b/\354\261\225\355\204\260_8/\354\204\234\354\244\200\355\231\230.md" new file mode 100644 index 0000000..8f23e8a --- /dev/null +++ "b/\354\261\225\355\204\260_8/\354\204\234\354\244\200\355\231\230.md" @@ -0,0 +1,195 @@ +# 자바스크립트 MV* 패턴 + +## 8.1 MVC 패턴 + +### M 모델 + +모델은 애플리케이션의 데이터를 관리 + +모델이 변경되었을 때 뷰에 변경사항을 알려주는 역할을 한다. + +> 뷰는 모델에 직접적으로 접근하지 않는다. + +### V 뷰 + +뷰는 모델에 대한 시각적인 표현 + +### C 컨트롤러 + +모델과 뷰를 연결하는 역할 + +모델과 뷰 사이의 중재자 역할을 한다. + + +#### 만약 리액트에서 구현한다면? + +```tsx +const userAPI = { + getUser: async (id: number): Promise => { + return { id, name: "John", email: "john@example.com" }; + }, + updateUser: async (id: number, name: string): Promise => { + 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(null); + const model = useMemo(() => new UserModelMVC(), []); + + useEffect(() => { + const unsubscribe = model.subscribe(() => { + setUser(model.getUser()); + }); + model.fetchUser(1); + return unsubscribe; + }, [model]); + + if (!user) return
Loading...
; + + return ( +
+

MVC Pattern

+ model.updateName(e.target.value)} + /> +
{user.email}
+
+ ); +}; +``` + +이렇게 되지 않을까? + +### 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(null); + const presenterRef = useRef(); + + useEffect(() => { + const model = new UserModelMVP(); + presenterRef.current = new UserPresenter(model, setUser); + presenterRef.current.loadUser(1); + }, []); + + if (!user) return
Loading...
; + + return ( +
+

MVP Pattern

+ presenterRef.current?.updateName(e.target.value)} + /> +
{user.email}
+
+ ); +}; +``` + +### 중간 정리 + +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 형태로 동작합니다. <- 이게 대체 뭔말인지 .,,, diff --git "a/\354\261\225\355\204\260_9/\354\204\234\354\244\200\355\231\230.md" "b/\354\261\225\355\204\260_9/\354\204\234\354\244\200\355\231\230.md" new file mode 100644 index 0000000..4872042 --- /dev/null +++ "b/\354\261\225\355\204\260_9/\354\204\234\354\244\200\355\231\230.md" @@ -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 등등,,