[第六章]インポートモードと画像-2
React Router Dom
動的ルーティングは、Webアプリケーションで実現できます.
React Router DOMは、従来のルーティングアーキテクチャ(ルーティングを実行するアプリケーションの外部構成で処理される)とは異なり、アプリケーションおよびプラットフォームの要件に応じてコンポーネントベースのルーティングを簡素化します.
Single Page Application(SPA)
反応はスパ!!
React Router Domのインストール
npm install react-router-dom --save
yarn add react-router-dom
React Routerの設定
インストールが完了したら、まず最初にしなければならないことは、アプリケーション内の任意の場所でReact Routerを使用できるようにすることです.
この操作を実行するには、srcフォルダでindexを使用します.jsファイルを開き、react-router-domからBrowserRouterをインポートし、ルートコンポーネントをカプセル化します.
複数の構成部品の作成と定義
Toだからリンクと差が少ない…!?
React Router Dom APIs
ネストされたルーティング
useNavigate
路線を変える.
useParams
パスパスにスタイル構文が使用されている場合は、userParams()を使用して読み込むことができます.
以下、invoicedIdとは何かを知るためにuseParamsを使用します.
useLocation
このHooksは現在の位置オブジェクトを返します.これは、現在の位置を変更するたびに何らかの副作用を実行する場合に便利です.
React Router DomをNetflixアプリケーションに適用する
実装する部分
ページを作成するフォルダとファイルを追加
Djangoを使用するように、ファイルを部分的に取り出します.
だから.
それぞれ出していくとアプリですjsファイルは以下のようになります.
import './App.css';
import Nav from "./components/Nav";
import Footer from './components/Footer';
import { Outlet, Route, Routes } from 'react-router-dom';
import DetailPage from './pages/DetailPage';
import MainPage from './pages/MainPage';
import SearchPage from './pages/SearchPage';
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=":movieId" element={<DetailPage/>} />
<Route path="search" element={<SearchPage/>} />
</Route>
</Routes>
</div>
);
}
export default App;
ルーターでかばって、ペヒの形を乗せます.パスのような場合は,ドメインの後ろに貼られていると考えられる.
Layoutにはすべてのページの汎用NavbarとFooterが含まれており、ページにも含まれています.
このまま!
だからMainPage/indexjsファイルを見てください.
import React from 'react'
import Banner from '../../components/Banner'
import Row from '../../components/Row'
import requests from '../../api/requests'
export default function MainPage() {
return (
<div>
<Banner/>
<Row
title="NETFLIX ORIGINALS"
id="NO"
fetchUrl={requests.fetchNetflixOriginals}
isLargeRow
/>
<Row
title="Trending Now"
id = "TN"
fetchUrl={requests.fetchTrending}
/>
<Row
title="Top Rated"
id = "TR"
fetchUrl={requests.fetchTopRated}
/>
<Row
title="Action Movies"
id = "AM"
fetchUrl={requests.fetchActionMovies}
/>
<Row
title="Comnedy Movies"
id = "CM"
fetchUrl={requests.fetchComedyMovies}
/>
</div>
)
};
これでいいです.でも終わりはindexjsへ
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
このようにBrowserRouterで包むには検索ページの実装
NavBarでの検索Inputの作成
<input value={searchValue} onChange={handleChange} className="nav__input" type="text" placeholder='영화제목을 입력해주세요.'></input>
inputを生成します.cssを生成して着る
const [searchValue, setsearchValue] = useState("");
const navigate = useNavigate();
const handleChange = (e) => {
setsearchValue(e.target.value); //바로 검색가능하다.
navigate(`/search?q=${e.target.value}`)
};
関数をください.入力するとすぐに検索されます.パスからvalueを取得して渡します.
useLocationが使用されます.
qのものを持ってきてくれれば、次のように表示されます.
import React from 'react'
import { useLocation } from 'react-router-dom'
export default function SearchPage() {
console.log('useLocation() : ',useLocation());
const useQuery =()=>{
return new URLSearchParams(useLocation().search);
}
let query = useQuery();
const searchTerm = query.get("q");
return (
<div>SearchPage</div>
)
}
SearchTermが変更されるたびに新しい映画データがインポートされます
import axios from "../../api/axios";
import React, { useEffect, useState } from 'react';
import { useLocation } from 'react-router-dom'
export default function SearchPage() {
const [searchResult, setsearchResult] = useState([]);
// console.log('useLocation() : ',useLocation());
const useQuery =()=>{
return new URLSearchParams(useLocation().search);
}
let query = useQuery();
const searchTerm = query.get("q"); //q에 있는걸 가져온다.
// console.log(searchTerm)
useEffect(() => {
if(searchTerm){
fetchSearchMovie(searchTerm);
}
}, [searchTerm]);
const fetchSearchMovie = async (searchTerm) =>{
try{
const request = await axios.get(
`/search/multi?include_adult=false&query=${searchTerm}`
)
setsearchResult(request.data.results);
}catch(error){
console.log("ERROR",error);
}
}
return (
<div>SearchPage</div>
)
}
検索するたびに新しい映画データがもたらされます.では今から映画と映画のないUIを作りましょう
検索ページUIの実装
SearchTermに対応する映画データが含まれている場合。
SearchTermに対応する映画データがない場合。
これは3つの演算子で解決されます.
import axios from "../../api/axios";
import React, { useEffect, useState } from 'react';
import { useLocation, } from 'react-router-dom'
import "./SearchPage.css";
export default function SearchPage() {
const [searchResult, setsearchResult] = useState([]);
const useQuery =()=>{
return new URLSearchParams(useLocation().search);
};
let query = useQuery();
const searchTerm = query.get("q"); //q에 있는걸 가져온다.
// console.log(searchTerm)
useEffect(() => {
if(searchTerm){
fetchSearchMovie(searchTerm);
}
}, [searchTerm]);
const fetchSearchMovie = async (searchTerm) =>{
try{
const request = await axios.get(
`/search/multi?include_adult=false&query=${searchTerm}`
)
setsearchResult(request.data.results);
}catch(error){
console.log("ERROR",error);
}
}
const renderSearchResults = () =>{
return searchResult.length > 0 ? (
<section className="search-container">
{searchResult.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">
</img>
</div>
</div>
)
}
})}
</section>
) : (
<section className="no-results">
<div className="no-results__text">
<p>
찾고자하는 검색어"{searchTerm}"에 맞는 영화가 없습니다.
</p>
</div>
</section>
);
};
return renderSearchResults();
}
useDeboring Custom Hooksの作成
Deboringって何?
不要な負荷を減らす.
hooksのuseDebocejsファイルを作成します.
import { useState,useEffect } from 'react'
export const useDebounce=(value,delay)=>{
const [DebounceValue,setDebounceValue] = useState(value);
useEffect(() => {
const handler = setTimeout(()=>{
setDebounceValue(value)
},delay);
return () => {
clearTimeout(handler);
};
}, [value, delay])
return DebounceValue;
}
それをSearchPageに持って行って使えばいいです.const debouncedSearchTerm = useDebounce(searchTerm, 500);
こんなふうに!その後、残りのsearchTermをdebonsedSearchTermに変換し、movieごとにkeyを1つずつ与えます.
ロードするたびにエラーがないのではなく、私が設定した時間でロードできることを確認できます.
ムービー詳細ページの表示
<div onClick={()=>navigate(`/${movie.id}`)} className="movie__column-poster">
これにより、映画の詳細ページをクリックしたときに移動できます.を選択します.
詳細ページの索引.jsファイルの作成
import axios from "../../api/axios"
import React, { useEffect, useState } from 'react'
import { useParams } from 'react-router-dom'
export default function DetailPage() {
const {movieId} = useParams();
const [movie, setMovie] = useState({});
useEffect(() => {
async function fetchData(){
const request = await axios.get(
`/movie/${movieId}`
)
setMovie(request.data)
}
fetchData();
}, [movieId])
if(!movie) return <div>...loading</div>;
return <section>
<img
className="modal__poster-img"
src={`https://image.tmdb.org/t/p/original/${movie.backdrop_path}`}
alt="poster"
/>
</section>
}
前述したようにイメージがあれば、そのままイメージを出します.
Reference
この問題について([第六章]インポートモードと画像-2), 我々は、より多くの情報をここで見つけました https://velog.io/@seochan99/chapter-6-모달-및-이미지-불러오기-2テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol