과제가 있다. MVVM 모델을 구현하여, REACT 앱을 만들어보는 과제였다.
우선 내가 아는 MVVM 모델을 생각해보면...
1. VIEW 에서 ACTION 을 VM 에 날린다.
2. 커맨드 패턴으로 VM 에 ACTION 을 전달한다.
3. VM 은 MODEL 에게 데이터를 요청한다.
4. MODEL 은 VM 에게 데이터를 응답한다.
5. VM 은 응답받은 데이터를 처리한다.
6. VM 은 VIEW 와 BIDING 하여 화면에 나타낸다.
이때, VM 은 VIEW 와 바인딩 되어있기에, 바로 처리가 된다.
하여튼 그래서 어떻게 해보았냐면...
1. MODEL (App.tsx)
모든 Data 를 저장하는 저장공간을 만들었다.
Redux-toolkit 을 사용하지 않고 하려니 고통이 이만저만 삼만사만이 아니었다.
import React, { useEffect, useState } from "react";
import { KrweurType, intialState, getEurInfo } from "./helper/get-euro-info";
import EuroToKrwController from "./view-models/euro-to-krw";
export const App = () => {
const [isReady, setReady] = useState<boolean>(false);
const [eurInfo, setEurInfo] = useState<KrweurType>(intialState);
const [inputedEuro, setInputedEuro] = useState<number>(0);
const [exchangedWon, setExchangedWon] = useState<number>(0)
const getEuroInfoState = (euroInfoState: KrweurType) => {
setEurInfo(() => euroInfoState);
};
...
const getExchangedWon = (exchangedWon : number) => {
setExchangedWon(()=> exchangedWon)
}
return (
<div className="App">
<EuroToKrwController
getReadyState={getReadyState}
...
inputedEuro={inputedEuro}
exchangedWon={exchangedWon}
/>
</div>
);
};
export default App;
모든 데이터를 저장하고, 컨트롤러인 Veiw-Model 로 "모든 값"과 "데이터를 가져오는 함수" 를 보냈다.
이것으로, Redux-toolkit 에서 사용하던 "구독" 을 구성해보았다.
이제, Model 은 VM 과 연결되었다.
2. VM(euro-to-krw.tsx)
모든 값을 받는 중간역할을 하게 만들었다.
MODEL 인 APP.TSX 와는 연결했으니, VIEW 로 그 값을 보내고,
VIEW 에서 보내주는 데이터를 받아, "처리" 하여 MODEL 을 업데이트 하는 역할을 시켰다.
MODEL 로 값을 보내기 위해, MODEL 로 "STATE 끌어올리기" 를 사용한다.
(MODEL 에서 GET 할 함수를 View-Model 로 보내주었음)
import { useEffect } from "react";
import { getEurInfo, KrweurType } from "../helper/get-euro-info";
import Information from "../views/Information";
import LoadingSpinner from "../views/Loading-spinner";
import InputPrice from "../views/Input-price";
const EuroToKrwController = (props: { // MODEL 에서 오는 모든 값과, MODEL 에서 데이터 받아갈 함수들
getReadyState: (readyState: boolean) => void;
getEuroInfoState: (euroInfoState: KrweurType) => void;
...
inputedEuro: number;
exchangedWon: number;
}) => {
const {
getReadyState,
getEuroInfoState,
...
inputedEuro,
exchangedWon,
} = props;
useEffect(() => {
getReadyState(true); // "로딩 STATE 를 모델로 넘김"
(async (): Promise<void> => {
const fetchedData = await getEurInfo(); // 데이터 페칭
getEuroInfoState(fetchedData); // "데이터 모델로 넘김"
getReadyState(false); // "로딩 STATE 를 모델로 넘김"
})();
return () => {};
}, []);
const exchangeEuroToKrw = (euro: number) => { // VIEW 의 값을 받아와 처리하는 로직
getEuroInputState(euro);
getExchangedWon(euro * eurInfo.basePrice); // VIEW의 값이 가공되면 다시 MODEL 로 보낸다.
};
return (
<div>
<Information eurInfo={eurInfo} /> // "VIEW 를 연결하고, VIEW에게 MODEL 에서 오는 값을 보낸다."
<hr />
{isReady && <LoadingSpinner />}
<InputPrice
exchangeEuroToKrw={exchangeEuroToKrw}
inputedEuro={inputedEuro}
exchangedWon={exchangedWon}
/>
</div>
);
};
export default EuroToKrwController;
3. VIEW ( 각 컴포넌트 )
VIEW 에서는 오로지 UI 만을 가지며,
ACTION(VM 에서 온 처리 로직) 을 VM 에 보낸다.
또한 VM 에서 가져온 최신 MODEL 데이터를 받고,
VM 으로는 자신의 최신 데이터를 보낸다
"양방향 바인딩" 을 이렇게 구현해보았다.
<Information.tsx>
import { Fragment } from "react";
import { KrweurType } from "../helper/get-euro-info";
const Information = (props: { eurInfo: KrweurType }) => {
const { eurInfo } = props;
return (
<Fragment>
<div>환율기준 (1 유로)</div>
<div>
{eurInfo.basePrice}
{eurInfo.basePrice - eurInfo.openingPrice > 0 && "▲"}
{eurInfo.basePrice - eurInfo.openingPrice < 0 && "▼"}
{eurInfo.changePrice}원 (
{(eurInfo.changePrice / eurInfo.basePrice) * 100}%)
</div>
<div>
<div>살때 : {eurInfo.cashBuyingPrice}</div>
<div>팔때 : {eurInfo.cashSellingPrice}</div>
<div>보낼때 : {eurInfo.ttSellingPrice}</div>
<div>받을때 : {eurInfo.ttBuyingPrice}</div>
</div>
</Fragment>
);
};
export default Information;
<Input-price.tsx>
import { Fragment } from "react";
const InputPrice = (props: {
exchangeEuroToKrw: (krw: number) => void;
inputedEuro: number;
exchangedWon: number;
}) => {
const { exchangeEuroToKrw, exchangedWon, inputedEuro } = props;
const commaEuro = inputedEuro.toLocaleString("en-US", {
maximumFractionDigits: 2,
});
const commaWon = exchangedWon.toLocaleString("ko-KR", {
maximumFractionDigits: 0,
});
return (
<Fragment>
<input
type={"number"}
onChange={(e) => exchangeEuroToKrw(+e.target.value)}
/>
<div>
<p> 인풋된 유로</p>
<p>{commaEuro} </p>
</div>
<div>
<p>유로 ▶︎ 원 </p>
<input type={"text"} disabled value={commaWon} /> 원
</div>
</Fragment>
);
};
export default InputPrice;
이게 정확히 맞는지는 모르겠다...
MVVM 디자인 패턴.. 어렵다...
아, 추가적으로 fetch 를 대신 해줄 helper 함수를 만들었다.
HELPER
export const getEurInfo = async ():Promise<KrweurType> => {
try {
const response = await fetch(
"https://quotat...EUR"
);
if (!response.ok) {
throw new Error("failed to fetch data");
}
const responseData = await response.json();
const krweurData = responseData[0];
return krweurData;
} catch (error) {
throw new Error("failed to fetch data");
}
};
export interface KrweurType {
code: string;
currencyCode: string;
currencyName: string;
country: string;
'React > React-TypeScript' 카테고리의 다른 글
12. helper 함수에 fetch를 정의하고, 가져올 때 Type을 지정해보자 (0) | 2023.01.16 |
---|---|
11. type? interface? 무엇을 써야 할까? (0) | 2022.12.29 |
10. Redux-toolkit 과 함께 Typescript 사용하기 (2) 실전, useRef 를 이용해 받은 값, Redux Store 에 넣기 (0) | 2022.12.27 |
9. Redux-toolkit 과 함께 Typescript 사용하기 (1)기본 사용 (0) | 2022.12.27 |
8. 코드의 타입을 모르겠다고? 걱정하지 말자! 마우스를 올려봐! (0) | 2022.12.26 |
댓글