react-js로 웹 서비스 만들기 4

·2020년 5월 21일
0

좌충우돌

목록 보기
5/26

4. Making the movie app

(0) Fetching Movies from API

<1> react lifecycle 다시보기

import React from "react";

class App extends React.Component {
    state = {
        // 미래에 추가할 state를 모두 처음에 declare할 필요는 없음.
        isLoading: true,
        movies: [],
    };
    componentDidMount() {
        setTimeout(() => {
            // setTimeout의 인자1: function, 인자2: 시간(ms 기준)
            this.setState({ isLoading: false });
        }, 3000);
    }
    render() {
        const { isLoading } = this.state;
        return (
            <div>   
                {isLoading ? "Loading..." : "We are ready"}
            </div>
        );
    }
}

export default App;

render() => mount => componentDidMount()
의 과정을 따라,
아래와 같이 1번 캡쳐의 내용이 3초간 화면에 표시된 이후에 2번 캡쳐의 내용이 뜬다.
1.
2.

왜 render 뒤에 mount를 하는데 render 내용대로 반영이 될까?

이건 render를 할 때 html을 박아두고, 거기에 component를 만들고(mount), componentDidMount()를 호출해서 박아둔 html 아래의 component에도 변화를 주기 때문 아닐까 싶다. 물론 이건 내 추측이다.

그럼 여기서 component는 이것 자체일까? App 자체?

이건 더 알아보자.

<2> fetch movie

import React from "react";
import axios from "axios";

class App extends React.Component {
    state = {
        // 미래에 추가할 state를 모두 처음에 declare할 필요는 없음.
        isLoading: true,
        movies: [],
    };
    getMovies = async () => {
        // async 알아보기
        const movies = await axios.get("https://yts.mx/api/v2/list_movies.json");
    }
    componentDidMount() {
        this.getMovies();
    }
    render() {
        const { isLoading } = this.state;
        return (
            <div>   
                {isLoading ? "Loading..." : "We are ready"}
            </div>
        );
    }
}

export default App;

async는 비동기 어쩌고, await 키워드를 쓴 코드를 기다려준다.
이건 또 알아보기

<3> Styling the movies + Adding Genres

// App.js
import React from "react";
import axios from "axios";
import Movie from "./Movie";
import "./App.css";

// FIXED: Since JSX is JavaScript, identifiers such as class and for are discouraged as XML attribute names. Instead, React DOM components expect DOM property names like className and htmlFor, respectively.

class App extends React.Component {
    state = {
        // 미래에 추가할 state를 모두 처음에 declare할 필요는 없음.
        isLoading: true,
        movies: [],
    };
    getMovies = async () => {
        // async 알아보기
        const {
            data: {
                data: { movies },
            },
        } = await axios.get("https://yts.mx/api/v2/list_movies.json");
        this.setState({ movies, isLoading: false });
    };
    componentDidMount() {
        // setTimeout(() => {
        //     // setTimeout의 인자1: function, 인자2: 시간(ms 기준)
        //     this.setState({ isLoading: false });
        // }, 3000);
        this.getMovies();
    }
    render() {
        const { isLoading, movies } = this.state;
        return (
            <section className="container">
                {isLoading ? (
                    <div className="loader">
                        <span className="loader__text">Loading....</span>
                    </div>
                ) : (
                    <div className="movies">
                        {/* <h1 className="document__head">Movies list</h1> */}
                        {movies.map((movie) => {
                            console.log(movie);
                            return <Movie key={movie.id} id={movie.id} year={movie.year} title={movie.title} summary={movie.summary} poster={movie.medium_cover_image} genres={movie.genres}></Movie>;
                        })}
                    </div>
                )}
            </section>
        );
    }
}

export default App;
// Movie.js
import React from "react";
import PropTypes from "prop-types";
import "./Movie.css";

// if component does not need "state", then 굳이 className component일 필요가 없음. 따라서 function component로.
// FIXED: props는 {}로 function의 인자로 넘김, key는 인자로 넘기는 것이 아니라고 함
function Movie({ id, year, title, summary, poster, genres }) {
    return (
        <div className="movie">
            <img src={poster} alt={title} title={title}></img>
            <div className="movie__data">
                <h3 className="movie__title">{title}</h3>
                <h5 className="movie__year">{year}</h5>
                <ul className="movie__genres">
                    {genres.map((genre, index) => (
                        <li key={index} className="genres__genre">
                            {genre}
                        </li>
                    ))}
                </ul>
                <p className="movie__summary">{summary.slice(0, 200) + "..."}</p>
            </div>
        </div>
    );
}

Movie.propTypes = {
    id: PropTypes.number.isRequired,
    year: PropTypes.number.isRequired,
    title: PropTypes.string.isRequired,
    summary: PropTypes.string.isRequired,
    poster: PropTypes.string.isRequired,
    genres: PropTypes.arrayOf(PropTypes.string).isRequired,
};

export default Movie;
/* App.css */
* {
    box-sizing: border-box;
}

body {
    margin: 0;
    padding: 0;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
    background-color: rgb(240, 240, 240);
    height: 100%;
}

html,
body,
#potato,
.container {
    height: 100%;
    display: flex;
    justify-content: center;
}

.loader {
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
}

.movies {
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
    padding: 50px;
    padding-top: 70px;
    align-items: flex-start;
    width: 80%;
}

.movies .movie {
    width: 45%;
    background-color: white;
    margin-bottom: 40px;
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    font-weight: 300;
    padding: 20px;
    position: relative;
    color: #5b6165;
    box-shadow: 5px 5px 6px grey;
}

.movie img {
    position: relative;
    top: -40px;
    max-width: 120px;
    margin-right: 30px;
}

.movie .movie__title,
.movie .movie__year {
    margin: 0;
    font-weight: 300;
}

.movie .movie__title {
    margin-bottom: 5px;
    font-size: 1.5em;
    font-weight: 400;
    color: black;
}

.movie .movie__genres {
    list-style: none;
    padding: 0;
    /* margin: 0; */
    display: flex;
    margin: 5px 0;
}

.movie__genres li {
    margin-top: 3px;
    margin-right: 10px;
    font-size: 20px;
}


결과 화면

아이폰으로는 잘 안된다. 아이폰으로 접속했을 때도 간지나게 하고 싶은데,, 쩝

profile
이것저것 개발하는 것 좋아하지만 서버 개발이 제일 좋더라구요..

0개의 댓글

관련 채용 정보