# React project movie-app ###### tags: `Javascript, React` 主要操作 react 跟著課程手把手把這個 project 完成,使用到 useState, useEffect ,練習 fetch API 以及 render 到頁面上 # [成品網址](https://chiehliu.github.io/movie-app/) ## 示意圖 ![](https://i.imgur.com/zSynULV.jpg) # 功能: * 可以搜尋電影 * 顯示電影大綱 * 顯示電影評分 * 有 default 圖片如果找不到的話 # JS 程式碼 ## 使用的 API * APIURL 主要使用來呈現 - 使用歡迎度來分類的第一頁的電影內容 * SEARCHAPI 則是可以在最後面的 query="" 字串串接上內容來搜尋資源 * IMGPATH 的部分就是呈現圖片 ```javascript= const APIURL = "https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=04c35731a5ee918f014970082a0088b1&page=1"; const SEARCHAPI = "https://api.themoviedb.org/3/search/movie?&api_key=04c35731a5ee918f014970082a0088b1&query="; const IMGPATH = "https://image.tmdb.org/t/p/w1280"; ``` ## App.js ```javascript= import React, { useEffect, useState } from 'react'; import Movie from './components/Movie'; const APIURL = "https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=04c35731a5ee918f014970082a0088b1&page=1"; const SEARCHAPI = "https://api.themoviedb.org/3/search/movie?&api_key=04c35731a5ee918f014970082a0088b1&query="; function App() { const [movies, setMovies] = useState([]); const [searchTerm, setSearchTerm] = useState(''); useEffect(() => { fetch(APIURL) .then(res => res.json()) .then(data => { console.log(data); // 這邊是目前第一頁呈現的所有電影內容並且指派給 movies setMovies(data.results); }) }, []) // 主要處理 submit 後利用使用者輸入的內容加上搜尋API 重新 fetch 內容並且更新 state const handleOnSubmit = (e) => { e.preventDefault(); if (searchTerm) { fetch(SEARCHAPI + searchTerm) .then(res => res.json()) .then(data => { console.log(data); // 這邊把搜尋到的 data.results 更新到 movies,因此頁面呈現只剩下搜尋的內容 setMovies(data.results); }); // 當 movies 被更新後搜尋欄位則被清空 setSearchTerm(''); } } // 這邊函式主要處理使用者在 search 輸入的內容要更新到 state searchTerm 裡面 const handleOnChange = (e) => { setSearchTerm(e.target.value) } return ( <div> <header> // 主要會在 form 表單加上 submit 事件監聽 <form onSubmit={handleOnSubmit}> <input type="search" className="search" placeholder="Search..." value={searchTerm} onChange={handleOnChange} /> </form> </header> <div className="movie-container"> // 使用 map 印出內容傳到 <Movie> 內部當作 props 傳遞給 movie.js component {movies && movies.map((movie) => <Movie {...movie} key={movie.id} /> )} </div> </div> ); } export default App; ``` ### 從 API 取得 Movie 的物件 * 取得物件(data)之後得從 json 轉回物件格式 * 接下來 setMovies 給 useState 中的 movies 使用 ```javascript= useEffect(() => { fetch(APIURL) .then(res => res.json()) .then(data => { console.log(data); setMovies(data.results); }) }, []) ``` ### render 資料上去 DOM 成品會有兩個部分 Search, movie 1. Search * 針對整個 form 做 onSubmit 事件處理 並使用`handleOnSubmit` 在 submit 時再次執行 fetch 這次的 url 會加入 搜尋用url+searchTerm ,最後使用找到的資料更新 DOM(就會只剩搜尋到的內容) * 對 value 的屬性做動態處理(上大括號) * 針對整個 form 做 onChange 事件處理 並使用`handleOnChange` 會把目前使用者輸入在 input 的內容更新進去 searchTerm 2. movie 使用 `&&` 運算子判斷式 如果 movies 不為空就正常 render 出 movies 內容 ```javascript= return ( <div> <header> <form onSubmit={handleOnSubmit}> <input type="search" className="search" placeholder="Search..." value={searchTerm} onChange={handleOnChange} /> </form> </header> <div className="movie-container"> {movies && movies.map((movie) => <Movie {...movie} key={movie.id} /> )} </div> </div> ); ``` ## Movie.js 當作子 component ,接收來自 App.js 的 props 使用解構的方式提取 results 的內容 poster_path, title, overview, vote_average 來呈現到瀏覽器上 ```javascript= const IMGPATH = "https://image.tmdb.org/t/p/w1280"; const Movie = ({ poster_path, title, overview, vote_average }) => { const setVoteClass = (vote) => { if (vote >= 8) { return 'green' } else if (vote >= 6) { return 'orange' } else { return "red" } } return ( <div className="movie"> <img src={poster_path ? (IMGPATH + poster_path) : 'https://images.unsplash.com/photo-1485846234645-a62644f84728?ixlib-rb-1.2.1&ixid=eyjhcHBfawQiOjEyMDd9&auto=format&fit=crop&w=1480&q=80'} alt={title} /> <div className="movie-info"> <h3>{title}</h3> <span className={`tag ${setVoteClass(vote_average)}`}>{vote_average}</span> </div> <div className="movie-over"> <h2>Overview:</h2> <p>{overview}</p> </div> </div> ); } export default Movie; ``` ### 預設圖片設置(如果電影圖片沒有正常顯示的話) 使用三元運算子操作 poster_path 是否為 true,如果為真則正常顯示`IMGPATH + poster_path` 為 false 的話顯示一張圖片的路徑當作預設圖片 ```javascript= <img src={poster_path ? (IMGPATH + poster_path) : 'https://images.unsplash.com/photo-1485846234645-a62644f84728?ixlib-rb-1.2.1&ixid=eyjhcHBfawQiOjEyMDd9&auto=format&fit=crop&w=1480&q=80'} alt={title} /> ``` ### 判斷式 處理顯示數字的顏色,針對 className 做函式操作添加的 class tag