[FrontEnd6] naver-movie-api를 이용하여 네이버 영화 검색 페이지 만들기 (router, naver-api, pagination, axios, query-string)

SMALL

안녕하세요~ 보라해바라기입니다!

 

오늘은 naver 영화 검색 api를 사용하여 라우터에 따른 영화검색 페이지를 만들어보았습니다:)

 

1. App.js

import './App.css';
import { Component } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Home from './components/Home.js'
import Search from './components/Search.js'
import InputComp from './components/InputComp.js'

class App extends Component {
  constructor(props){
    super(props)
    this.state={

    }
  }

  render(){
    return (
      <div id='app'>
        <BrowserRouter>
          <InputComp/>
          <Routes>
            <Route exact path='/' element={<Home/>}/>
            <Route exact path='/search' element={<Search/>}/>
          </Routes>
        </BrowserRouter>
      </div>
    );
  }
}

export default App;

 

2. App.css

#app{
  width: 1100px;
  height: 1400px;
  margin: 0 auto;
  background-color: aliceblue;
}

 

3.Home.js

import { Component } from 'react';
import '../css/Home.css'

class Home extends Component {
    constructor(props){
        super(props)
        this.state={

        }
    }

    render(){
        return(
            <div id='home'>
                home
            </div>
        )
    }
}


export default Home;

 

4.Home.css

#home{
    width: 1000px;
    height: 1000px;
    background-color: thistle;
}

 

5.Search.js

import { Component } from 'react';
import '../css/Search.css'
import axios from 'axios'
import queryString from 'query-string'
import MovieList from './MovieList.js'
import Pagination from './Pagination.js';

//search한 값을 pagination

class Search extends Component {
    constructor(props){
        super(props)
        this.state={
           movieList:[],
           currentPage:1,
           moviePerPage:3
        }
    }

    componentDidMount(){
    //    console.log('Search')
    //   console.log('window.location', window.location) // host, hostname, href, pathname. port...
    //    console.log('window.location.href', window.location.href) 
        // http://localhost:3000/search?searchText=블라블라블라&display=10&country=JPN
    //    console.log('window.location.search', window.location.search)
        // ?searchText=블라블라블라&display=10&country=JPN
        const queryObj=queryString.parse(window.location.search)
    //    console.log(queryObj) // {country: 'JPN', display: '10', searchText: '스파이더맨'}
    //    console.log(queryObj.searchText) //스파이더맨
        const searchText = queryObj.searchText
        this.searchMovie(searchText)
    }

    searchMovie=async(searchText)=>{
        const {movieList} = this.state
        console.log(searchText)
        const axios_movies = await axios({
            method:'get',
            url:`/v1/search/movie.json?query=${searchText}`,
            dataType:'json',
            headers:{
                "X-Naver-Client-Id": "OCTOqeR_MCymgnyep8zR",
                "X-Naver-Client-Secret": "_UO4OJzKop"
            }
        })
        this.setState({
            movieList:axios_movies.data.items
        })
        console.log(axios_movies.data.items)
        console.log(movieList)
    }

    setCurrentPage=(page)=>{
        alert("페이지 설정(App.js):"+page)
        this.setState({
            currentPage:page
        })
    }

    currentMovieList=(movieList)=>{
        const {currentPage, moviePerPage} = this.state
        const indexFirst = (currentPage-1)*moviePerPage
        const indexLast = indexFirst+moviePerPage
        const slicedMovieList = movieList.slice(indexFirst, indexLast)
        return slicedMovieList;
    }

    

    render(){
        const {movieList, moviePerPage, currentPage} = this.state
        return(
            <div id='search'>
                <MovieList movieList={this.currentMovieList(movieList)}/>
                <Pagination movieListLength={movieList.length} currentPage={currentPage}
                moviePerPage={moviePerPage} setCurrentPage={this.setCurrentPage}/>
            </div>
        )
    }
}


export default Search;

 

6.Search.css

#search{
    width: 1000px;
    height: auto;
    background-color: lightgreen;
}

 

7.InputComp.js

import { Component } from 'react';
import '../css/InputComp.css'

class InputComp extends Component {
    constructor(props){
        super(props)
        this.state={
            searchText:''
        }
    }

    searchBook=()=>{
        alert("책 검색")
        window.location.href=`/search?searchText=${this.state.searchText}&display=10&country=JPN`
    }

    inputChange=(e)=>{
        this.setState({
            searchText:e.target.value
        })
    }

    render(){
        return(
            <div id='input-comp'>
                <input type='text' placeholder='검색어' onChange={this.inputChange}/>
                <button onClick={this.searchBook}>검색</button>
            </div>
        )
    }
}


export default InputComp;

 

8.InputComp.css

#input-comp{
    width: 1000px;
    height: 50px;
    margin-bottom: 10px;
    background-color: lightpink;
}

 

9.Movie.js

import { Component } from 'react';
import '../css/Movie.css';

class Movie extends Component {
  constructor(props){
    super(props)
    this.state={
    
    }
  }

  render(){
    return (
      <div id="movie">
        <div id='left-side'>
            {this.props.image}
        </div>
        <div id='right-side'>
            <span>제목: {this.props.title} </span>
            <span>년도: {this.props.pubDate} </span>
            <span>감독: {this.props.director}</span>
            <span>배우: {this.props.actor}</span>
            <span>평점: {this.props.userRating}/10</span>
        </div>
      </div>
    );
  }
}

export default Movie;

 

10.Movie.css

#movie{
    width: 900px;
    height: 300px;
    background-color: yellowgreen;
    margin: 10px;
}

#movie>#left-side{
    float: left;
    width: 250px;
    height: 290px;
    background-color: lightpink;
    padding-top: 30px;
    padding-left: 40px;
    box-sizing: border-box;
}

#movie>#right-side{
    float: left;
    width: 550px;
    height: 290px;
    background-color: lightblue;
}

#movie>#right-side>span{
    display: block;
    width: 540px;
    height: 35px;
    padding-top: 10px;
    box-sizing: border-box;
}

#movie>#right-side>span:first-child{
    background-color: lightgray;
}

#movie>#right-side>span:nth-child(2){
    background-color: lightgoldenrodyellow;
}

#movie>#right-side>span:nth-child(3){
    background-color: lightcyan;
}

#movie>#right-side>span:nth-child(4){
    background-color: sandybrown;
    height: auto;
}

#movie>#right-side>span:nth-child(5){
    background-color: plum;
}

 

11.MovieList.js

import { Component } from 'react';
import '../css/MovieList.css';
import Movie from './Movie';

class MovieList extends Component {
  constructor(props){
    super(props)
    this.state={
    
    }
  }

  // 제목에 나오는 html태그 제거해야 함 -> (구글링: react 태그 제거 ~ replace)

  render(){
    const result= this.props.movieList.map(
        (data) => (<Movie key={data.id} 
        image = {<img src= {data.image}/>}
        title={data.title.replace(/(<([^>]+)>)/ig,"")} 
        pubDate={data.pubDate} director={data.director.replace(/(<([^>]+)>)/ig,"").replace(/\|/ig,",")}
        actor={data.actor.replace(/(<([^>]+)>)/ig,"").replace(/\|/ig,",")} userRating={data.userRating}/>)
    )

    // data.title.replace(/(<([^>]+)>)/ig,"") => 모든 태그를 제거
    // data.director.replace(/\|/ig,",") => |를 한꺼번에 바꾸기 (| 앞에 무효화할 수 있도록 \키 넣기)

    return (
      <div id="movie-list">
        {result}
      </div>
    );
  }
}

export default MovieList;

 

12.MovieList.css

#movie-list{
    width: 900px;
    height: auto;
    margin: 0 auto;
}

img{
    width: 180px;
    height: 230px;
}

 

13.Pagination.js

import { Component } from 'react';
import '../css/Pagination.css';

class Pagination extends Component {
  constructor(props){
    super(props)
    this.state={
    
    }
  }

  setCurrentPage=(page)=>{
    alert(page+"페이지 클릭(Pagination.js)")
    this.props.setCurrentPage(page)
  }

  prevPage=()=>{
    alert("이전")

    const {currentPage, setCurrentPage} = this.props
    if (currentPage==1){
        alert("여기는 첫 페이지 입니다.")
        return
    }
    setCurrentPage(currentPage-1)
  }

  nextPage=()=>{
    alert("다음")

    const {currentPage, setCurrentPage} = this.props
    const {lastPageNum} = this.state

    if (currentPage+1 > lastPageNum){
        alert("여기는 마지막 페이지 입니다.")
        return
    }
    setCurrentPage(currentPage+1)
  }

  render(){
    const {movieListLength, moviePerPage} = this.props

    let pageNumbers=[];
    const lastPageNum = Math.ceil(movieListLength/moviePerPage)
    for(var i=1; i<=lastPageNum; i++){
        pageNumbers.push(i)
    }

    const result=pageNumbers.map(
        (data)=>(<span className='page' key={data}
        onClick={()=>this.setCurrentPage(data)}>{data}</span>)
      )

    return (
      <div id="pagination">
        <div>
            총 글 갯수: {movieListLength}
        </div>
        <div>
            페이지당 글 갯수: {moviePerPage}
        </div>
        <div>
            <span className='page' onClick={this.prevPage}>
                &lt;
            </span>
            <span>{result}</span>
            <span className='page' onClick={this.nextPage}>
                &gt;
            </span>
        </div>
      </div>
    );
  }
}

export default Pagination;

 

14.Pagination.css

#pagination{
    width: 900px;
    height: 100px;
    background-color: springgreen;
    position: relative;
    margin-left: 60px;
}

.page{
    display:inline-block;
    width:35px;
    height:35px;
    border:1px solid black;
    margin:5px;
    text-align: center;
    padding-top:5px;
    box-sizing: border-box;
    background-color: darkgray;
    cursor: pointer;
}

#pagination>div:nth-child(3){
    position: absolute;
    left: 240px;
}

15. 실행결과

"스파이더맨"을 검색했을 때, 네이버 영화 api에서 data를 받아와 페이지네이션으로 출력

728x90

댓글