axios, Popup 컴포넌트 활용, css 종횡비 지정
학원 수업 Day18
useState() 복습
학습했던 hook 사용법을 복습했다.
조건문으로 State 변경
let [ time, setTime ] = useState(1);
function btnSetTime() {
time = time >= 12 ? 1 : time + 1;
setTime(time);
}
<div>
<span>타이머 : {time}시</span>
<button onClick={btnSetTime}>Update</button>
</div>
input값 받아서 리스트 추가
실시간으로 input의 입력값을 받아와서 버튼 클릭 시 배열에 추가하여 화면에 출력한다.
추가 후에는 인풋 내용을 비워준다.
let they = ['오렌지', '딸기'];
const [fruits, setFruits] = useState(they);
const [input, setInput] = useState('');
console.log(setInput);
function insertInput(e) {
setInput(e.target.value);
}
function onUpload() {
setFruits((prev)=>{
return [...prev, input];
});
setInput('');
}
<div>
<input type="text" value={input} onChange={insertInput} />
<button onClick={onUpload}>Upload</button>
{
name.map((data, i)=>{
return <p key={i}>{data}</p>;
})
}
</div>
useEffect()
화면에 렌더링 되는 개체를 여러 개 만들어서 각자 렌더링 될 때마다 이벤트가 실행되도록 할 수 있다.
const [count, setCount] = useState(1);
const [name, setName] = useState('');
function update() {
setCount(count + 1);
}
function inputUpdate(e) {
setName(e.target.value);
}
useEffect(() => {
console.log('렌더링 되었습니다.');
}) // 매 렌더링 마다 발생
useEffect(() => {
console.log('마운트 되었습니다.');
}, []) // 마운트시에만 발생
useEffect(() => {
console.log('count 렌더링 되었습니다.');
}, [count]) // count 렌더링 시에만 발생
useEffect(() => {
console.log('name 렌더링 되었습니다.');
}, [name]) // name 렌더링 시에만 발생
<div>
<button onClick={update}>Update</button>
<span>count : {count}</span>
<input type="text" value={name} onChange={inputUpdate} />
</div>
axios
vanilla JS로 제작할 때는 fetch를 배웠는데, react로 제작하면서 axios를 배웠다.
Axios | Fetch |
---|---|
써드파티 라이브러리 설치 필요 | 내장 라이브러리로 설치 불필요 |
호환성이 뛰어남 | 크롬 42+, firefox 39+, edge 14+, safari 10.1+ 지원 (polyfill 이용해서 하위 호환성 지원 가능) |
XSRF Protection 보안 기능 제공 | 없음 |
자동으로 JSON 데이터로 변환 | JSON 데이터로 바꿔 주어야 함 |
요청 취소와 타임아웃 설정 가능 | 없음 (AbortController 이용하여 구현 가능) |
HTTP Requests 의 Intercept 가능 | Intercept Requests 기본적으로 제공되지 않음 (Global Fetch Method를 Overwrite 하여 나의 인터셉터 정의 가능) |
Download 요청에 대해 기본적인 지원 | Upload Progress 지원안함 (Response Object의 Body Property 통해 제공되는 ReadableStream 인스턴스 이용 가능) |
사용법
axios는 설치해서 사용해야하는 라이브러리로 터미널에서 아래 명령어로 설치한다.
npm install axios
import axios from 'axios';
axios.create({
baseURL: 'https://www.googleapis.com/youtube/v3',
params: { key: '키값' },
})
.get('추가경로')
.then((json)=>{
받아온 데이터 처리;
})
useEffect 로 마운트 할때 적용한다.
기본 파라미터
-
key(필수) : string;
발급받은 키 -
part : string;
–videoid
단일 영상ID –snippet
관련된 영상들 -
maxResults : number;
영상 결과 최대 개수 -
q : string;
검색어 -
type : string;
‘video’로 설정 -
videoDuration : string;
길이 ( long : 20분이상 )
기본 레이아웃 서브메뉴 추가
Department 페이지
DB가 따로 없어서 수기로 json 데이터를 만들어서 뽑아오는 연습을 했다.
{
"members": [
{
"name": "이름",
"position": "직업",
"pic": "이미지 파일명.jpg"
}
]
}
const path = process.env.PUBLIC_URL;
const [Members, setMembers] = useState([]);
useEffect(() => {
axios.get(`${path}/db/members.json`).then((json)=>{
setMembers(json.data.members);
})
}, [])
useEffect(() => { // 데이터 확인용
console.log(Members);
}, [Members])
JSX에서는 Members를 map()
으로 돌려서 출력시켰다.
JSX return 내부에서 JS코드 사용 시 중괄호로 둘러주는 것에 유의해야 한다.
아직 중괄호 사용이 어색하다.
Youtube 페이지
youtube에서 제공하는 API를 활용해서 미리 설정한 플레이리스트를 받아와서, useEffect로 마운트 시 뿌려준다.
const url = `https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&key=${key}&playlistId=${playlist}&maxResults=${num}`;
const [videos, setVideos] = useState([]);
const [open, setOpen] = useState(false);
const [index, setIndex] = useState(0);
useEffect(() => {
axios.get(url).then((json)=>{
setVideos(json.data.items);
})
}, [])
JSX에서는 역시나 map()
으로 하나씩 출력 해 줬다.
출력 시 제목과 내용은 너무 길지 않도록 substring()
으로 일부 잘라냈고, 날짜 데이터 또한 시간은 뜨지 않도록 split()
으로 배열로 변환하여 활용했다.
클릭 시 Popup 컴포넌트도 불러왔다.
<>
<Layout name='youtube'>
{videos.map((data, index)=>{
let title = data.snippet.title;
let description = data.snippet.description;
let date = data.snippet.publishedAt;
if(title.length > 30) title = title.substring(0, 30) + '...';
if(description.length > 100) description = description.substring(0, 100) + '...';
date = date.split('T')[0];
return (
<article key={index}>
<div className="txt">
<h3>{title}</h3>
<p>{description}</p>
<span>{date}</span>
</div>
<div className="pic" onClick={()=>{ setOpen(true); setIndex(index)}}>
<img src={data.snippet.thumbnails.standard.url} alt={data.snippet.title} />
</div>
</article>
);
})}
</Layout>
{ open && <Popup setOpen={setOpen}>
<iframe src={`https://www.youtube.com/embed/${videos[index].snippet.resourceId.videoId}`} frameBorder="0"></iframe>
</Popup> }
</>
Popup 컴포넌트 마운트
-
상단에서
const [open, setOpen] = useState(false);
로 컴포넌트 마운트 조건을 만들어 준다.
– 최초값false
-
클릭 시
()=>{setOpen(true)}}>
으로useState()
를 사용해서 마운트 조건을true
로 바꿔준다. -
&&
로 마운트 조건이true일
시에만 Popup 컴포넌트를 불러온다.
–&&
: 앞 내용true
시 뒷 내용 실행 -
JSX내 Popup컴포넌트 호출 태그의 인라인요소로
iframe
을 넣어 Popup컴포넌트에서props.children
으로 내용을 받아올 수 있도록 했다.
오픈 시useState()
로 index값을 변경해 해당 값을 사용하도록 했다.
– 오픈 이벤트의 코드는 아래와 같다.
onClick={()=>{ setOpen(true); setIndex(index)}}
-
닫기 구현을 위해 클릭 시 이벤트에
setOpen={setOpen}
를 prop으로 넘긴다. -
Popup 컴포넌트 내 close버튼 클릭 시 이벤트에
props.setOpen(false)
를 주어 open 값을false
로 변경한다.
Body 스크롤 방지
useEffect()
를 사용해서 Popup 상태 시 Body의 스크롤이 되지 않도록 했다.
useEffect() 내에서 return 시 clean-up을 함수를 실행할 수 있다고 이론으로만 배웠는데, 이렇게 활용하는구나 싶었다.
useEffect(() => {
document.body.style.overflow = 'hidden';
// Popup 마운트 시 body 스크롤 방지
return (()=>{
document.body.style.overflow = 'auto';
// Popup 언마운트 시 body 스크롤 실행
})
}, [])
종횡비 css 적용
유튜브 영상의 종횡비 고정을 위해 css를 추가했다.
기존 css
.outer{
width: 500px;
/* 가로 값 지정 */
.inner{
padding-top: calc(100% / 16 * 9);
/* 16:9 비율 */
}
}
간편해진 css
aspect-ratio: 16 / 9;
MDN에 찾아보니 다양한 브라우저에서 다 지원하던데, 브라우저 별 버전에 관한 내용은 잘 모르겠다.
익스플로러는 호환이 되지 않을지도?