react axios요청 & styled-component
업데이트:
카테고리: react
/API 문서
axios 요청
axios 설치 : npm install axios --save
axios.get()
을 이용하여 해당 홈페이지에 요청한다.
src/api/axios.js
를 생성하여 해당 파일에 기본 axios 요청을 설정한다.
import axios from 'axios';
// 기본이 되는 설정을 세팅한다.
const instance = axios.create({
baseURL: "https://api/themoviedb.org/3",
params: {
api_key: "bb3738ca53fd0213d09143e2353c91ce",
language: "ko-KR"
},
});
export default instance;
// src/api/requests.js
// 요청 url들을 담아둔다.
const requests = {
fetchNowPlaying: "movie/now_playing",
fetchNetflixOriginals: "/discover/tv?with_networks=213",
fetchTrending: "/trending/all/week",
fetchTopRated: "/movie/top_rated",
fetchActionMovies: "/discover/movie?with_genres=28",
fetchComedyMovies: "/discover/movie?with_genres=35",
fetchHorrorMovies: "/discover/movie?with_genres=27",
fetchRomanceMovies: "/discover/movie?with_genres=10749",
fetchDocumentaries: "/discover/movie?with_genres=99",
};
export default requests;
스크롤시 NavBar 색깔 변경
nav 스타일에 해당 코드 입력
transition-timing-function: ease-in;
transition: all 0.5s;
[transition](https://developer.mozilla.org/ko/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions) 은 애니메이션, 속성에 변화가 생길때 일정 기간에 걸쳐 보여주는 함수이다.
// src/components/Nav.js
// 스크롤을 감지하여 어느정도 밑으로 내려가면 검은색 배경화면이 나오도록 설정
useEffect(() => {
// 스크롤이 있을때 해당 함수 실행
window.addEventListener("scroll", () => {
if(window.scrollY > 50) {
setShow(true);
} else {
setShow(false);
}
})
return () => {
// 스크롤이 없으면 이벤트 삭제
window.removeEventListener("scroll", () => {})
}
});
이미지 배너 생성
랜덤한 영화를 가져오기 위해 Math.floor(Math.random() * 10)
을 사용
useEffect(() => {
fetchData();
}, []);
const fetchData = async () => {
// 현재 상영중인 영화정보 요청 (20개의 데이터가 들어있다.)
const request = await axios.get(requests.fetchNowPlaying);
// movie 데이터 안에서 랜덤으로 돌린다
const movieId = request.data.results[Math.floor(Math.random() * request.data.results.length)].id;
// 특정영화의 데이터 가져오기
// {response.data = movieDetail} 에 할당한다.
const {data: movieDetail} = await axios.get(`movie/${movieId}`, {
params: {append_to_response: "videos"}
})
setMovie(movieDetail)
};
글자 생략하기
const truncate = (str, n) => {
return str?.length > n ? str.substr(0, n-1) + '...' : str;
}
글자가 존재하고 해당 글자가 n 개를 넘어간다면 n번째 이후는 …으로 대체, 아니면 그대로 출력
@media 란?
미디어 유형에 따라 만족할 경우에만 css블럭을 적용함
- all : 모든 유형에 적합
- print : 인쇄 결과물이나 미리보기 화면에서 표시중인 문서
- screen : 화면이 대상
- speech : 음성 합성장치 대상
Styled Component
Js 안에서 Css 코드를 처리하는 라이브러리
npm install --save styled-components
를 이용하여 설치
return (
<Container>
<HomeContainer>
clicked
</HomeContainer>
</Container>
)
// 함수 바깥에 해당 형식으로 작성
// 어떤 태그인지 어떤 스타일을 먹일지 변수로 저장후 return에서 컴포넌트 처럼 사용한다.
const Container = styled.div`
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
width: 100%;
height: 100vh;
`
const HomeContainer = styled.div`
width: 100%;
height: 100%
`
React Router Dom
웹앱에서 동적 라우팅 구현가능, 컴포넌트 기반에 라우팅을 용이하게 한다.
⇒ SPA
를 구성하기 위해서 하나의 페이지만 처음에 로딩하고 필요한 컴포넌트를 라우팅으로 변화시킨다.
설치: npm install react-router-dom --save
초기설정 : src폴더의 index.js파일에서 BrowserRouter
를 구성하고 루트 구성을 안에 넣어준다.
URL과 UI를 동기화 시켜준다.
라우터 설정
Routes
: 앱에서 생성될 모든 개별 경로에 대한 상위 역할, 모든 컴포넌트 중 첫번째 컴포넌트가 반환
Route
: 단일 경로를 만드는데 사용
path
: 컴포넌트에 URL를 지정,\
로 구성된 컴포넌트는 처음 로드될 때 먼저 랜더링 된다.element
: 해당 경로에 맞는 컴포넌트를 지칭
Link
: Router에서 지정한 경로를 이동할 수 있다.
중첩 라우팅
// 보여줄 레이아웃 구성
const Layout = () => {
return (
<div>
<Nav/>
<Outlet/>
<Footer/>
</div>
)
}
// 중첩 라우팅 구성
function App() {
return (
<div className="App">
<Routes>
<Route path="/" element={<Layout/>}>
<Route index element={<MainPage/>}/>
<Route path=":movidId" element={<DetailPage/>}/>
<Route path="search" element={<SearchPage/>}/>
</Route>
</Routes>
</div>
);
}
코드 내에서 어떤 URL 에 따라 어떤 컴포넌트를 로드 할것 인지 작성
코드를 어지럽히지 않고 깔끔하게 작성이 가능하다.
⇒ useRouteshook
을 이용해서 작성이 가능하다.
Outlet
자식 경로 요소를 랜더링할려면 부모 경로에서 <Outlet>
을 사용해야된다. 하위 경로가 랜더링 될때 중첩된 UI 표시가능
함수
useNavigate
: 경로를 바꿔준다. 해당 경로로 이동useParams
: path를 읽어올 수 있다. 동적으로 데이터를 가져오기가 가능useLocation
: 현재 위치를 반환, 위치가 변경될때 마다 side effect를 수행할때 유용- hash: “”
- key: “1afzzwsd”
- pathname: “/search”
- search: “?q=%EC%95%BC%ED%98%B8”
- state: null
⇒ 해당 형식으로 path와 쿼리… 다양한 정보를 반환해준다.
검색 페이지 구현
-
검색 바 생성
const navigate = useNavigate(); const handleChange = (e) => { setSearchValue(e.target.value); navigate(`/search?q=${e.target.value}`) };
⇒ 영화 검색 단어를 작성할 때마다 페이지를 이동하도록 한다
-
검색어 데이터 가져오기
const useQuery = () => { return new URLSearchParams(useLocation().search); } let query = useQuery(); // q에 적혀있는 내용을 가져오게된다. const searchTerm = query.get("q") useEffect(()=> { if (searchTerm) { fetchSearchMovie(searchTerm); } // 해당 데이터가 변할때마다 useEffect 데이터를 실행 }, [searchTerm]); const fetchSearchMovie = async (searchTerm) => { try { const request = await axios.get(`/search/multi?include_adult=false&query=${searchTerm}`) console.log(request); setSearchResults(request.data.results); } catch (error) { console.error(error) } }
⇒ 쿼리에 있는 데이터를 가져와 변경될 때 마다 새로운 데이터를 가져온다.
-
UI 호출
const renderSearchResults = () => { return searchResults.length > 0 ? ( // 검색 결과가 존재할 때 <section className='search-container'> {searchResults.map((movie) => { if (movie.backdrop_path !== null && movie.media_type !== "person") { const movieImageUrl = "https://image.tmdb.org/t/p/w500" + movie.backdrop_path return ( <div className='movie'> <div className='movie__column-poster'> <img src={movieImageUrl} alt="movie" className='movie__poster'/> </div> </div> ) } })} </section> // 존재하지 않을 때 ) : <section className='no-results'> <div className='no-results__text'> <p> 찾고자 하는 검색어 "{searchTerm}"에 맞는 영화가 없습니다. </p> </div> </section> }; return renderSearchResults();
⇒ render할 부분을 따로 함수로 빼두어서 조건에 따라 랜더링 파트를 조절할 수 있다.
Debounce
검색에 입력할 때 결과가 나타날 때까지 지연이 있다. debounce function에 의해 제어하고 있기 때문
UI 코드가 모든 검색어를 처리할 필요가 없어 성능이 향상될 수 있음
react에서 hook 제작
useFucntion
형식으로 파일을 만든다.
import { useState, useEffect } from "react";
export const useDebounce = (value, delay) => {
const [debounceValue, setDebounceValue] = useState(value);
useEffect(() => {
//
const handler = setTimeout(() => {
setDebounceValue(value)
}, delay);
// dalay전에 데이터가 들어온다면
// handler의 딜레이를 초기화 시켜준다.
return () => {
clearTimeout(handler);
}
// 값이 바뀌거나 딜레이가 바뀐다면
}, [value, delay]);
return debounceValue;
}
영화 상세페이지 구현
- 클릭시 상세페이지로 이동
<div
className='movie__column-poster'
onClick={() => navigate(`/${movie.id}`)}>
- 상세페이지에서 데이터 가져오기
// 영화 id가 변경될때마다 아래 함수를 실행
useEffect(() => {
async function fetchData() {
const request = await axios.get(`/movie/${movieId}`);
console.log(request.data)
setMovie(request.data);
}
fetchData();
}, [movieId]);
모달창 외부 클릭 시 모달창 닫기
useRef
: 특정 DOM 을 선택하는 리액트 훅
- 클래스 컴포넌트 ⇒
React.createRef
- 함수형 컴포넌트 ⇒
useRef
특정 돔을 잡고싶을때 ref={ref}
을 넣어주면 해당 Dom을 잡을 수 있다.
이것을 이용해서 모달창 외부면 모달 창이 닫히도록 설계!
import React, { useEffect } from 'react'
const useOnClickOutSide = (ref, handler) => {
useEffect(() => {
const listener = (event) => {
console.log(ref.current)
// 내부를 클릭하고 있으면 아무 반응 없음
if (!ref.current || ref.current.contains(event.target)) {
return ;
}
// 외부를 클릭하면 닫힘
handler(); //setModalOpen(false);
};
document.addEventListener("mousedown", listener);
document.addEventListener("touchstart", listener);
// 언마운트 되었을 때 함수를 제거함
return () => {
document.removeEventListener("mousedown", listener);
document.removeEventListener("touchstart", listener);
};
}, []);
}
export default useOnClickOutSide;
Swiper
공식문서를 참고해서 Swiper를 구현
Swiper하고싶은 큰틀을 Swiper
로 감싸고 각 리스트 원소를 SwiperList
로 감싼다.