MVC패턴
모델Model : 모델은 앱이 포함해야할 데이터가 무엇인지를 정의. ( ==데이터베이스 )
뷰View: 레이아웃과 화면을 처리합니다.(==화면 jsx, vue)
컨트롤러Controller: 명령을 모델과 뷰 부분으로 라우팅합니다. (==비동기통신하는 부분, composable)
mvc패턴으로 짜주려면 누구 하나가 모든것을 다 처리하면 안된다.
각각의 역할 만큼만 할 수 있도록 만들어주어야한다.
따라서 view에서 비동기통신과 관련된 것들을 모~두 하지 않는것이 좋고, 따로 services 폴더를 만들어 관리한다.
수정 전 코드 app.jsx
import './App.css';
import React, {useState, useEffect} from 'react';
import VideoList from './components/video_list/index.jsx';
import Search from './components/search/index.jsx';
function App({ youtube }) {
const [ videos, setVideos ] = useState([]);
const apikey = '123456789testkey';
const requestOptions = {
method: 'GET',
redirect: 'follow'
};
useEffect(() => {
console.log('effect')
fetch(
`https://www.googleapis.com/youtube/v3/videos?part=snippet&chart=mostPopular&maxResults=25&type=video&key=${apikey}`
, requestOptions
)
.then(response => response.json())
.then(result => setVideos(result.items))
.catch(error => console.log('error', error));
}, [])
const handleSearch = (data) => {
const url = 'https://www.googleapis.com/youtube/v3/search'
fetch(
`${url}?part=snippet&q=${data}&maxResults=25&type=video&key=${apikey}`
, requestOptions
)
.then(response => response.json())
.then(result => result.items.map(item => ({...item, id: item.id.videoId })))
.then(items => setVideos(items))
.catch(error => console.log('error', error));
}
return (
<React.Fragment>
<Search handleSearch={handleSearch}></Search>
<VideoList videos={videos}></VideoList>
</React.Fragment>
);
}
export default App;
언뜻봐도 알겠지만 모든 통신을 app.jsx 파일에서, 즉 view에서 모든 것을 컨트롤하고 있는 상태이다.
MVC 패턴으로 수정하기
1. src밑에 services 폴더 만들고 하위에 index.ts 파일 만들기
//services/index.ts
class Youtube {
constructor(key) {
this.key = key;
this.requestOptions = {
method: 'GET',
redirect: 'follow'
};
}
async mostPopular() {
console.log('key', this.key)
try {
const response = await fetch(
`https://www.googleapis.com/youtube/v3/videos?part=snippet&chart=mostPopular&maxResults=25&type=video&key=${this.key}`,
this.requestOptions
);
const result_1 = await response.json();
return result_1.items;
} catch (error) {
return console.log('error', error);
}
}
async search(query) {
const url = 'https://www.googleapis.com/youtube/v3/search'
try {
const response = await fetch(
`${url}?part=snippet&q=${query}&maxResults=25&type=video&key=${this.key}`,
this.requestOptions
);
const result_1 = await response.json();
return result_1.items;
} catch (error) {
return console.log('error', error);
}
}
}
export default Youtube;
2. src/index.js 에서 인스턴스 새로 만들어서 선언해두기 (각 페이지에서 하는것은 좋지 않음)
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import Youtube from './services/youtube';
const youtube = new Youtube(process.env.REACT_APP_YOTUBE_API_KEY);
ReactDOM.render(
<React.StrictMode>
<App youtube={youtube} />
</React.StrictMode>,
document.getElementById('root')
);
youtube 를 선언해서 그 안에 services에서 받아온 Youtube class를 새로 만들어서 App 컴포넌트로 넘겨준다.
여기서 new Youtube() 안의 apikey부분은 env 파일을 만들어서 따로 관리한다. (관련 내용은 아래 url 참고)
3. src/app.jsx 에서 (필요한 페이지에서 ) 넘긴 youtube 가져다가 사용하기
import './App.css';
import React, {useState, useEffect} from 'react';
import VideoList from './components/video_list/index.jsx';
import Search from './components/search/index.jsx';
function App({ youtube }) {
const [ videos, setVideos ] = useState([]);
const handleSearch = (query) => {
youtube
.search(query)
.then(items => setVideos(items));
}
useEffect(() => {
youtube
.mostPopular()
.then(items => setVideos(items));
}, []);
return (
<React.Fragment>
<Search handleSearch={handleSearch}></Search>
<VideoList videos={videos}></VideoList>
</React.Fragment>
);
}
export default App;
반응형
'React' 카테고리의 다른 글
[React & 환경세팅] .env 환경변수 파일 값 변경하기 (0) | 2022.03.16 |
---|---|
[React] useEffect란 ? ? ? (0) | 2022.02.24 |
[React] 깃허브에 올리면 안되는 apikey 설정하는법 (.env 파일) (0) | 2022.02.21 |
[React 세팅] 리액트 create-react-app 세팅 오류 ! (You are running `create-react-app` 4.0.1, which is behind the latest release (5.0.0).) (0) | 2022.02.09 |
[React 기본] React Hook (0) | 2022.02.07 |