[第六章]インポートモードと画像-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を使用するように、ファイルを部分的に取り出します.
    だから.
  • MainPage
  • SearchPage
  • DetailPage
    それぞれ出していくとアプリですjsファイルは以下のようになります.
  • App.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>
    }
    前述したように
    イメージがあれば、そのままイメージを出します.