For Programmer

5.LandingPage만들기(3) Load More Button - 영화사이트만들기 본문

React & Node.js 프로젝트/영화사이트 만들기

5.LandingPage만들기(3) Load More Button - 영화사이트만들기

유지광이 2020. 7. 28. 22:47
728x90

*loadMoreFunction 만들기(LandingPage.js)

1. button에 onclick 이벤트설정

<div style={{ display: 'flex', justifyContent: 'center' }}>
        <button onClick={loadMoreItems}>Load More</button>
      </div>

2. state값에 현재페이지값 저장

const [CurrentPage, setCurrentPage] = useState(0);

2.fetch 통신코드가 중복이 되기 때문에 코드낭비를 방지하기위해서 하나의 변수에 저장한다.

const fetchMovies = (endpoint) => {
    fetch(endpoint)
      .then((response) => response.json()) //응답을 json형태로 변경하여 then의 response에 반환
      .then((response) => {
        console.log(response);
        setMovies([...Movies, ...response.results]); //console로 찍어보면 results배열에 담겨서 데이터보내줌
        //스프레드 연산자를 사용하여 배열에 집어넣음
        setMainMovieImage(MainMovieImage || response.results[0]);
        //로딩될때는 MainMovieImage값이 null이기 때문에 response.results[0]값이 들어오며
        //그다음 loding button을 눌릴때마다 MainMovieImage즉 초기이미지로 고정이된다.
        //안그러면 로그창에 오류발생
        setCurrentPage(response.page);
      });
  };

*단 마지막에 serCurrentPage(response.page)가 추가 되었는데 그이유는 뒤에나올 loadMoreItems함수에서 fetch통신을 위한 마지막인자 page값을 계속해서 버튼을 눌릴때마다 1씩 올려주어야하기때문이다. (response.page는 1을 반환)

3.loadMoreItems 함수 만들기

const loadMoreItems = () => {
    const endpoint = `${API_URL}movie/popular?api_key=${API_KEY}&language=en-US&page=${CurrentPage + 1}`;
    fetchMovies(endpoint);
  };

 

Landingpage.js의 전체코드

import React, { useEffect, useState } from 'react';
import { withRouter } from 'react-router-dom';
import { API_URL, API_KEY, IMAGE_BASE_URL } from '../../Config';
import MainImage from './Sections/MainImage';
import GridCards from '../commons/GridCards';
import { Row } from 'antd';

const LandingPage = (props) => {
  const [Movies, setMovies] = useState([]); //배열로 값을받기 때문
  const [MainMovieImage, setMainMovieImage] = useState(null);
  const [CurrentPage, setCurrentPage] = useState(0);

  useEffect(() => {
    const endpoint = `${API_URL}movie/popular?api_key=${API_KEY}&language=en-US&page=1`;
    fetchMovies(endpoint);
  }, []);

  const fetchMovies = (endpoint) => {
    fetch(endpoint)
      .then((response) => response.json()) //응답을 json형태로 변경하여 then의 response에 반환
      .then((response) => {
        console.log(response);
        setMovies([...Movies, ...response.results]); //console로 찍어보면 results배열에 담겨서 데이터보내줌
        //스프레드 연산자를 사용하여 배열에 집어넣음
        setMainMovieImage(MainMovieImage || response.results[0]);
        //로딩될때는 MainMovieImage값이 null이기 때문에 response.results[0]값이 들어오며
        //그다음 loding button을 눌릴때마다 MainMovieImage즉 초기이미지로 고정이된다.
        //안그러면 로그창에 오류발생
        setCurrentPage(response.page);
      });
  };
  const loadMoreItems = () => {
    const endpoint = `${API_URL}movie/popular?api_key=${API_KEY}&language=en-US&page=${
      CurrentPage + 1
    }`;
    fetchMovies(endpoint);
  };
  return (
    <div style={{ width: '100%', margin: '0' }}>
      {/*Main Image */}
      {MainMovieImage && ( //만약 이러한 작업을 하지않을 경우 React는 MainMovieImage를 state에 넣기전에
        //페이지를 렌더링 할려고 하여 backrop_path가 null 에러가 발생한다.

        /*console.log 보면 backdrop_path에 이미지에대한 이름이 담겨있다.*/
        <MainImage
          image={`${IMAGE_BASE_URL}w1280/${MainMovieImage.backdrop_path}`} //영화이미지
          title={MainMovieImage.original_title} //영화제목
          text={MainMovieImage.overview} //영화에대한설명
        />
      )}

      <div style={{ width: '85%', margin: '1rem auto' }}>
        <h2>Movies by latest</h2>
        <hr />

        {/*Movie Grid Cards */}
        <Row gutter={[16, 16]}>
          {/*gutter는 Col간의 위 아래여백을 줄때 사용 */}
          {Movies &&
            Movies.map((movie, index) => (
              <React.Fragment key={index}>
                <GridCards
                  image={
                    movie.poster_path
                      ? `${IMAGE_BASE_URL}w500/${movie.poster_path}`
                      : null
                  }
                  movieName={movie.original_title}
                  movieId={movie.id}
                />
              </React.Fragment>
            ))}
        </Row>
      </div>

      <div style={{ display: 'flex', justifyContent: 'center' }}>
        <button onClick={loadMoreItems}>Load More</button>
      </div>
    </div>
  );
};

export default withRouter(LandingPage);

 

*번외로 페이스북이나 인스타그램처럼 밑으로 계속해서 스크롤을 내릴경우 자동으로 데이터를 불러오는 코드를 만들고 싶다면 다음코드를 이용하면된다.(LandingPage.js)

import React, { useEffect, useState, useRef } from 'react';
import { Typography, Row, Button } from 'antd';
import { API_URL, API_KEY, IMAGE_BASE_URL } from '../../Config';
import MainImage from './Sections/MainImage';
import GridCard from '../commons/GridCards';

const { Title } = Typography;

function LandingPage() {
  const buttonRef = useRef(null);
  const [Movies, setMovies] = useState([]);
  const [MainMovieImage, setMainMovieImage] = useState(null);
  const [Loading, setLoading] = useState(true);
  const [CurrentPage, setCurrentPage] = useState(0);

  useEffect(() => {
    const endpoint = `${API_URL}movie/popular?api_key=${API_KEY}&language=en-US&page=1`;
    fetchMovies(endpoint);
  }, []);

  useEffect(() => {
    window.addEventListener('scroll', handleScroll);
  }, []);

  const fetchMovies = (endpoint) => {
    fetch(endpoint)
      .then((result) => result.json())
      .then((result) => {
        setMovies([...Movies, ...result.results]);
        setMainMovieImage(MainMovieImage || result.results[0]);

        setCurrentPage(result.page);
      }, setLoading(false))

      .catch((error) => console.error('Error:', error));
  };

  const loadMoreItems = () => {
    let endpoint = '';
    setLoading(true);
    console.log('CurrentPage', CurrentPage);
    endpoint = `${API_URL}movie/popular?api_key=${API_KEY}&language=en-US&page=${
      CurrentPage + 1
    }`;

    fetchMovies(endpoint);
  };

  const handleScroll = () => {
    const windowHeight =
      'innerHeight' in window
        ? window.innerHeight
        : document.documentElement.offsetHeight;

    const body = document.body;
    const html = document.documentElement;

    const docHeight = Math.max(
      body.scrollHeight,
      body.offsetHeight,
      html.clientHeight,
      html.scrollHeight,
      html.offsetHeight
    );
    const windowBottom = windowHeight + window.pageYOffset;

    if (windowBottom >= docHeight - 1) {
      console.log('clicked');
      buttonRef.current.click();
    }
  };

  return (
    <div style={{ width: '100%', margin: '0' }}>
      {MainMovieImage && (
        <MainImage
          image={`${IMAGE_BASE_URL}w1280/${MainMovieImage.backdrop_path}`}
          title={MainMovieImage.original_title}
          text={MainMovieImage.overview}
        />
      )}

      <div style={{ width: '85%', margin: '1rem auto' }}>
        <Title level={2}> Movies by latest </Title>

        <hr />

        <Row gutter={[16, 16]}>
          {Movies &&
            Movies.map((movie, index) => (
              <React.Fragment key={index}>
                <GridCard
                  image={
                    movie.poster_path
                      ? `${IMAGE_BASE_URL}w500/${movie.poster_path}`
                      : null
                  }
                  movieId={movie.id}
                  movieName={movie.original_title}
                />
              </React.Fragment>
            ))}
        </Row>

        {Loading && <div>Loading...</div>}

        <br />

        <div style={{ display: 'flex', justifyContent: 'center' }}>
          <button ref={buttonRef} className="loadMore" onClick={loadMoreItems}>
            Load More
          </button>
        </div>
      </div>
    </div>
  );
}

export default LandingPage;

https://github.com/jinyowo/JS-Calendar/wiki/**offsetHeight,-innerWidth-%EC%99%80-%EB%B9%84%EC%8A%B7%ED%95%9C-%EC%86%8D%EC%84%B1%EB%93%A4-%EC%A0%95%EB%A6%AC

* 위의 길이를 구할때 쓰는 ScrollHeight,offsetHeight,clientHeight 등에대한 설명이 자세하게 나와있다.

https://sometimes-n.tistory.com/22

* innerHeight,outerHeight 등에 대한 내용이 자세하게 나와있다.

실행결과

동영상강의

 

728x90
Comments