NomadCoder React(2)

박영빈·2023년 5월 13일

멋쟁이사자처럼

목록 보기
3/5

멋쟁이사자처럼 5주차 과제

7. Practice Movie App

To Do List


import { useState, useEffect } from "react";
// import styles from "./App.module.css";

function App() {
  const [toDo, setToDo] = useState("");
  const [toDos, setToDos] = useState([]);
  // 할일을 저장하는 배열 선언
  const onChange = (event) => {
    setToDo(event.target.value);
  };
  const onSubmit = (event) => {
    event.preventDefault();
    if (toDo === "") {
      return;
    }
    setToDos((prev) => [toDo, ...prev]);
    // toDos.push X => 직접 수정하지 않음
    // 배열에 추가하기 위해선 ... 작성법 활용
    // todo 작성하고 submit하면 배열 앞에 할 일 추가
    setToDo("");
  };
  return (
    <div>
      <h1>My To Dos ({toDos.length})</h1>
      <form onSubmit={onSubmit}>
        <input
          onChange={onChange}
          value={toDo}
          type="text"
          placeholder="Write your to do..."
        />
        <button>Add To Do</button>
      </form>
      <hr />
      <ul>
        {toDos.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
    </div>
  );
}
// list.map() => 괄호 안의 함수를 모든 원소에 대해 실행
//['a', 'b', 'c'].map((item)=>item.toUpperCase()) => ['A','B','C']
// 이 함수를 사용하여 ul, li로 구현
// 위처럼 구현하면 console에 경고가 뜨는데, 각 요소에 key를 지정해야 한다고 한다.

export default App;
  • 전부 앞에서 배운 개념들을 활용하였다.
  • 추가적으로 배운 개념만 적자면
    • state로 배열을 지정할 수 있다는 점과 배열을 변경할 땐 … 표시법 잘 활용하기
    • map함수를 이용하여 배열 값들을 활용하기

Coin Tracker

import { useState, useEffect } from "react";
// import styles from "./App.module.css";

function App() {
  const [loading, setLoading] = useState(true);
  const [coins, setCoins] = useState([]);
  const [selected, setSelected] = useState(false);
  const [money, setMoney] = useState(0);
  useEffect(() => {
    fetch("https://api.coinpaprika.com/v1/tickers")
      .then((response) => response.json())
      .then((json) => {
        setCoins(json);
        setLoading(false);
      });
  }, []);
  // coin정보를 가져다주는 API를 활용하여 json으로 파싱하여 출력
  function onChange(event){
    setMoney(event.target.value);
  }
  function coinChange(event){
    setSelected(coins[event.target.selectedIndex])
  }
  // console.log(coins);
  return (
    <div>
      <h1>The Coins ({coins.length})</h1>
      {loading ? <strong>Loading...</strong> : null}
      <select onChange={coinChange}>
        {coins.map((coin) => (
          <option key={coin.id}>
            {coin.name} ({coin.symbol}) : ${coin.quotes.USD.price} USD
          </option>
        ))}
      </select>
      <br></br>
      <span>if you have </span>
      <input type="number" onChange={onChange} value={money}/><span> $</span>
      <br></br>
      {selected ? <div><span>{selected.name} : </span><span>{money / selected.quotes.USD.price}</span></div>:null}
    </div>
  );
}

export default App;
  • coin 정보를 불러오는 api를 활용한 실습
  • JSON 형태의 데이터를 받아와서 활용해보았다.
  • 마지막으로 니꼬쌤이 해보라고 한 도전과제까지 완료
    • 내가 입력한 달러에 따라 얼마만큼의 코인을 구매할 수 있는지 구현 완료

Movie App

// .../src/component/Movie.js
import PropTypes from "prop-types";

function Movie({coverImg, title, summary, genres}) {
  return (
    <div>
        <img src={coverImg} alt={title} />
        <h2>{title}</h2>
        <p>{summary}</p>
        <ul>
          {genres.map((g) => (
            <li key={g}>{g}</li>
          ))}
        </ul>
        <hr />
    </div>
  );

  Movie.propTypes= {
    coverImg:PropTypes.string.isRequired,
    title:PropTypes.string.isRequired,
    summary:PropTypes.string.isRequired,
    genres:PropTypes.arrayOf(PropTypes.string).isRequired,
  }
}
export default Movie;
  • 하나의 영화 설명 div를 정의한 js파일
  • 이 컴포넌트를 호출하는 쪽에서 같이 보낸 props를 활용하여 컴포넌트를 완성한다.
// .../src/route/Home.js
import { useState, useEffect } from "react";
import Movie from "./components/Movie.js";

function Home() {
  const [loading, setLoading] = useState(true);
  const [movies, setMovies] = useState([]);
  const getMovies = async () => {
    const json = await (
      await fetch(
        "https://yts.mx/api/v2/list_movies.json?minimum_rating=8.5&sort_by=year"
      )
    ).json();
    // 이전에 썼던 then과 동일한 기능, 보편적으로 사용
    setMovies(json.data.movies);
    setLoading(false);
  };
  useEffect(() => {
    getMovies();
  }, []);
  return (
    <div>
      {loading ? (
        <h1>Loading...</h1>
      ) : (
        <div>
          {movies.map((movie) => (
            <Movie
              key={movie.id}
              coverImg={movie.medium_cover_image}
              title={movie.title}
              summary={movie.summary}
              genres={movie.genres}
            />
          ))}
        </div>
      )}
    </div>
  );
}

export default Home;
  • 메인 화면을 나타내는 page
  • 영화 api를 통해 데이터를 불러오고 Movie 컴포넌트를 활용해 전체 정보를 출력한다.
  • Route 기능은 다음 챕터에!

React Router

import React from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
//react router를 사용하기 위해 임포트
import Home from "./routes/Home.js";
import Detail from "./routes/Detail";

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/hello" element=<h1>Hello</h1>/>
        <Route path="/movie" element={<Detail />}/>
        <Route path="/" element={<Home />}/>
      </Routes>
    </Router>
  );
}

export default App;
  • switch는 route를 찾는 역할, route는 url을 의미함
  • 강의에서는 Switch를 사용했지만 업데이트 돼서 Route에 element 이렇게 써야 함
  • Link를 만들어서 이동하게 하고 싶다 -> 일반적으로 <a href~~>를 쓴다고 생각할 수 있지만 이 경우 페이지 전체가 리로드됨
  • a태그 대신에 react-router-dom의 Link를 Movie.js에서 import해서 대신 사용

import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";

function Detail() {
  const { id } = useParams();
  const [loading, setLoading] = useState(true);
  const [movie, setMovie] = useState();
  const getMovie = async () => {
    const json = await (
      await fetch(`https://yts.mx/api/v2/movie_details.json?movie_id=${id}`)
    ).json();
    setMovie(json.data.movie);
    setLoading(false);
    console.log(movie);
  };
  useEffect(() => {
    getMovie();
  }, []);
  return (
    <div>
      {loading ? (
        <h1>Loading...</h1>
      ) : (
        <div>
          <img src={movie.large_cover_image} alt={movie.title} />
          <h2>Title : {movie.title}</h2>
          <p>Rating : {movie.rating}</p>
          <p>Running Time : {movie.runtime}</p>
          <p>Description : {movie.description_full}</p>
        </div>
      )}
    </div>
  );
}
// useParams를 사용하여 url parameter를 받을 수 있음
export default Detail;
function App() {
  return (
    <Router>
      <Routes>
        <Route path="/hello" element=<h1>Hello</h1>/>
        <Route path="/movie/:id" element={<Detail />}/>
        <Route path="/" element={<Home />}/>
      </Routes>
    </Router>
  );
}
  • Detail 페이지로 이어지도록 라우팅 한 뒤, Detail 페이지도 Home 페이지와 비슷하게 구성해두었다.
  • path에 :id 같이 작성하여 변수를 받을 수 있다.
  • useParams를 사용하여 url parameter를 받을 수 있다.

Publishing

  • github pages를 이용해 배포하기
  • npm i gh-pages npm run build
  • pakage.json 파일에 가서 맨 마지막에 콤마 찍고 "homepage":"https://username.github.io/Repositoryname" 추가
  • scripts에 추가 (predeploy를 작성하면 위의 build 생략해도 됨
"deploy":"gh-pages -d build", 
"predeploy":"npm run build"
  • npm run deploy 를 실행하자
  • 자동으로 우리가 만든 코드를 이용해 배포해준다.
  • 배포 완료 github page 최고 React App
  • css로 꾸미는건 차근차근해보자

13. Conclusion

  • 앞서 했던 deploy와 별 다른 내용이 없어서 따로 정리는 하지 않았다.
profile
안녕하세요<br>반가워요<br>안녕히가세요

0개의 댓글