---
# System prepended metadata

title: Netflix - React、Redux （ㄧ）

---

# Netflix - React、Redux （ㄧ）

### 環境建置

> $ npx creat-react-app netflix-build --template redux

### Firebase

[firebase](https://firebase.google.com/)

註冊一個帳號，點選右上角 ==前往主控台==，新增專案

繼續之後點選 </> (網頁)，跟著步驟下一步
記得勾選`一併為這個應用程式設定 Firebase 代管功能` ，因為之後要部署此應用程式

###### install Firebase CLI

> $ sudo npm install -g firebase-tools

完成之後，Firebase SDK snippet 勾選 config

複製此段代碼到專案建立一個firebase.js，之後會用到

```javascript=
const firebaseConfig = {
  apiKey: "AIzaSyA3OyAW0HLSX3R6s-dJRogcUEq9OJ-DxQ8",
  authDomain: "test-94387.firebaseapp.com",
  projectId: "test-94387",
  storageBucket: "test-94387.appspot.com",
  messagingSenderId: "374698696816",
  appId: "1:374698696816:web:691ca1e26039b7ad6e94b5"
};
```

### TMDB拿取api__key

1. 使用TMDB API除了要先註冊使用者帳號之外還要再取得API Key，登入帳號後到大頭照那邊點一下，接著點選Settings到設定頁面。  
2. 進入Settings頁面後可以看到API的選項，點進去後可以看到指示，依指示進行填資料、送出資料。選擇Web送出資料之後會看到大頭照旁邊的小鈴鐺亮起，點進去會看到自己的API Key送來了。
3. Settings的API頁面，也會看到自己的API Key出現在這裡。

### axios建置

Axios特性
1、可以在瀏覽器中發送 XMLHttpRequests
2、可以在 node.js 發送 http 請求
3、支持 Promise API
4、攔截請求和響應
5、轉換請求數據和響應數據
6、能夠取消請求
7、自動轉換 JSON 數據
8、客戶端支持保護安全免受 XSRF 攻擊

原文網址：https://kknews.cc/code/rl8leyo.html

> $ yarn add axios

建立一個axios.js

```javascript=
import axios from "axios";

const instance = axios.create({
  baseURL: "https://api.themoviedb.org/3",
  // 需要 TMDB API的網址
});

export default instance;

```


在這之前先仔細閱讀了一下[TMDB API](https://developers.themoviedb.org/3/getting-started/introduction/)文件


建立一個Requests.js

```javascript=
const API_KEY = "523883aef3c6707e0d55a6077e404958";

const requests = {
  fetchTrending: `/trending/all/week?api_key=${API_KEY}&language=en-US`,
  fetchNexflixOriginals: `/discover/tv?api_key=${API_KEY}&with_networks=213&language=en-US`,
  fetchTopRated: `/movie/top_rated?api_key=${API_KEY}&language=en-US`,
  fetchActionMovie: `/discover/movie?api_key=${API_KEY}&with_genres=28`,
  fetchComedyMovie: `/discover/movie?api_key=${API_KEY}&with_genres=35`,
  fetchHorrorMovie: `/discover/movie?api_key=${API_KEY}&with_genres=27`,
  fetchRomanceMovie: `/discover/movie?api_key=${API_KEY}&with_genres=10749`,
  fetchDocumentaries: `/discover/movie?api_key=${API_KEY}&with_genres=99`,
};

export default requests;

```

在[TMDb genre ID values](https://www.reddit.com/r/radarr/comments/70egj8/tmdb_genre_id_values/)找到相關電影類型，方便之後頁面分類。

### React UI

> $ yarn start

    開啟一個local端3000

開啟App.js，create component `<HomeScreen />`，建立一個首頁UI

在<HomeScreen />裡有 `<Nav />、<Banner />、<Row />` component


### <Nav />

在`<Nav />`
```javascript=
const [show, handleShow] = useState(false);

  const transitionNavBar = () => {
    if (window.scrollY > 100) {
      handleShow(true);
    } else {
      handleShow(false);
    }
  };

  useEffect(() => {
    window.addEventListener("scroll", transitionNavBar);
    return () => window.removeEventListener("scroll", transitionNavBar);
  }, []);
```
```javascript=
<div className={`nav ${show && "nav__black"}`}>
```

在css裡`nav position:fixed`置頂最上方，`nav__black background-color: black`

就可以往下捲軸時超過100，nav的背景就為黑色

---

### <Banner />

在`<Banner />` banner__description裡有個小技巧，可以用一個function讓過多的文字以 ... 呈現

```javascript=
function truncate(string, n) {
    return string?.length > n ? string.substr(0, n - 1) + "..." : string;
  }
```

```javascript=
<h1 className="banner__description">
          {truncate(movie?.overview, 150)}
</h1>
```

:::warning
如果description超過150個字，就以 "..."取代。
:::

> 在Banner頁面裡，拿取TMDB API資料，以隨機方式切換電影資訊
> 
```javascript=
  const [movie, setMovie] = useState([]);

  useEffect(() => {
    async function fetchData() {
      const request = await axios.get(requests.fetchNexflixOriginals);
      setMovie(
        request.data.results[
          Math.floor(Math.random() * request.data.results.length - 1)
        ]
      );
      return request;
    }
    fetchData();
  }, []);
```
:::warning
TMDB API裡圖片的取得有些限制，必須先指定欲取得的圖片尺寸，才能夠取得圖片資料。

尺寸的URL為：https://image.tmdb.org/t/p/+圖片url
![](https://i.imgur.com/N04XuUF.png)

```
backgroundImage: 
`url("https://image.tmdb.org/t/p/original/${movie?.backdrop_path}")`
```
:::

---

### <HomeScreen />
`import requests from "../Requests"`

```javascript=
function HomeScreen() {
  return (
    <div className="homescreen">
      <Nav />

      <Banner />

      <Row
        title="NEXFLIX ORIGINALS"
        fetchUrl={requests.fetchNexflixOriginals}
        isLargeRow
      />
      <Row title="Trending Now" fetchUrl={requests.fetchTrending} />
      <Row title="Top Rated" fetchUrl={requests.fetchTopRated} />
      <Row title="Action Movies" fetchUrl={requests.fetchActionMovie} />
      <Row title="Comedy Movie" fetchUrl={requests.fetchComedyMovie} />
      <Row title="HorrorMovie" fetchUrl={requests.fetchHorrorMovie} />
      <Row title="Romance Movie" fetchUrl={requests.fetchRomanceMovie} />
      <Row title="Documentaries" fetchUrl={requests.fetchDocumentaries} />
    </div>
  );
}
```
### <Row />

`import axios from "./axios"`
```javascript=
function Row({ title, fetchUrl, isLargeRow = false }) {
  const [movies, setMovies] = useState([]);

  const base_url = "https://image.tmdb.org/t/p/original/";

  useEffect(() => {
    async function fetchData() {
      const request = await axios.get(fetchUrl);
      setMovies(request.data.results);
      return request;
    }
    fetchData();
  }, [fetchUrl]);

  return (
    <div className="row">
      <h2>{title}</h2>
      <div className="row__posters">
        {movies.map(
          (movie) =>
            ((isLargeRow && movie.poster_path) ||
              (!isLargeRow && movie.backdrop_path)) && (
              <img
                className={`row__poster ${isLargeRow && "row__posterLarge"}`}
                key={movie.id}
                src={`${base_url}${
                  isLargeRow ? movie.poster_path : movie.backdrop_path
                }`}
                alt={movie.name}
              />
            )
        )}
      </div>
    </div>
  );
}

```

在css的小技巧裡，讓不想要有滾動條可以在css裡這樣設置
```javascript=
.row__posters {
  display: flex;
  overflow-y: hidden;
  overflow-x: scroll;
  padding: 20px;
}

.row__posters::-webkit-scrollbar {
  display: none;
}
```

