컨버스 클로닝-인스타그램 기능의 모든 것!(모달창, 다음 버튼, 더보기 기능) 👍

이병수·2020년 8월 2일
0

TIL

목록 보기
19/19
post-thumbnail

위코드 1차 프로젝트 컨버스(Converse) 클론 프로젝트 중 저의 가장 큰 과제였던 인스타그램 기능 구현에 대한 리뷰 글입니다. 💕

인스타 페이지 구조는 아래와 같다.
main > InstaPage > InstaList > InstaBox , InstaModal

모달창

모달창 Open

인스타리스트 페이지
인스타박스와 인스타 모달의 상단 컴포넌트로 인스타 페이지의 값을 받아와 모달과 박스에 해당 값을 뿌려준다.

class InstaList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      currentModalIdx: null,
      modalState: false,
      data: [],
    };
  }
  
  
  modalStateHandler = (index) => {
    const { modalState } = this.state;
    this.setState({
      modalState: !modalState,
      currentModalIdx: index,
    });
    document.body.style.overflow = "hidden";
  };

1) modalState로 불리언 값에 따라 모달창이 띄워지게 세팅, 하단 컴포넌트인 인스타 박스에 modalStateHandler라는 함수를 props로 전달하여 해당 박스 클릭 시 상단 컴포넌트인 인스타리스트 modalState값이 변경되게 만든다.
2) 동시에 같은 props로 currentModalIdx라는 현재의 인덱스 값을 null로 비워두고 해당 인스타박스 클릭 시 그 인덱스 번호가 채워지게 만든다.

모달창 Close

인스타리스트


closeModal = (e) => {
  if (e.target.className === "InstaModal") {
    this.setState({
      modalState: false,
    });
  }
  document.body.style.overflow = "unset";
};

인스타모달


    <div className="InstaModal" onClick={this.props.closeModal}>

모달창을 띄웠지만 어떻게 close하는 방법에 대해서도 애를 먹었는데 e.target.className으로 해결! closeModal를 인스타 모달창에 props로 전달 해당 배경화면(전체를 감싸는 div)가 InstaModal일 경우 modalState의 값을 다시 false로 변경하여 모달창 close

모달창 다음 / 이전 버튼


> 인스타리스트 
nextIdxHandler = (index) => {
  const { currentModalIdx } = this.state;
  this.setState({
    currentModalIdx: currentModalIdx + 1,
  });
};

backIdxHandler = (index) => {
  const { currentModalIdx } = this.state;
  this.setState({
    currentModalIdx: currentModalIdx - 1,
  });
};

> 인스타모달 
class InstaModal extends Component {
clickNextHandler = () => {
  this.props.nextIdxHandler();
};

clickBackHandler = () => {
  this.props.backIdxHandler();
};

render() {
  const { user, image, text, user_profile_image } = this.props.data[0];
  let changedText = text.split("%").join("\n");

  return (
    <div className="InstaModal" onClick={this.props.closeModal}>
      <button className="backBtn" onClick={this.clickBackHandler}>
        <IoIosArrowBack className="btn" />
      </button>

모달창의 백버튼을 클릭시 clickBackHandler가 실행 이것은 상단인 인스타리스트의 backIdxHandler가 실행되어 currentModalIdx의 값이 변경되게 된다
넥스트 버튼도 위와 마찬가지이다 그럼 어떻게 되냐 ?

> 인스타리스트 
  render() {
    const { posts } = this.props;
    const { currentModalIdx, modalState } = this.state;
    let data = posts.filter((item, index) => index === currentModalIdx);
> 인스타모달
render() {
    const { user, image, text, user_profile_image } = this.props.data[0];

인스타 모달창에 전달되는 data는 필터함수로 currentModalIdx 값과 같은 것으로 필터되어 전달 인스타 모달창은 결국 현재의 인덱스에 따라 모든 데이터가 출력되도록 설정 😭😂
요고 생각하기 넘나 어려웠다 ㅠㅠㅠㅠㅠ

더보기 기능(Pagenation)

const LIMIT = 8;

class InstaPage extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      posts: [],
      offset: 0,
      loading: false,
    };
  }

offset은 보여주고자 하는 페이지의 시작점이라 생각하면 된다. loading을 불리언으로 관리해서 true가 될 시 로딩 로고창이 뜨게 만들었다. LIMIT은 몇개까지 보여줄 것인에 대한 것으로 변함없는 값으로 상수로 관리한다.


  clickViewMore = () => {
    const { offset, posts, loading } = this.state;

    this.setState(
      {
        offset: offset + 1,
        loading: true,
      },
      () => {
        fetch(`${instaAPI}?page=${this.state.offset}&limit=${LIMIT}`)
          .then((res) => res.json())
          .then((res) => {
            this.setState(
              {
                posts: [...this.state.posts, ...res.posts],
              },
              () => {
                this.setState({ loading: false });
              }
            );
          });
      }
    );
  };

클릭이 일어났을 때 setState으로 offset값과 loading값을 변화시켜준다.
콜백함수로 fetch함수를 호출시켜 res에 넣고 그것을 spread operator를 통해 다시 기존의 post의 데이터와 함치는 과정을 거친다. 그리고 다시 loading의 state값을 false로 바꿔 로딩 로고창이 없어지게 만든다.

  
  componentDidMount() {
    const { offset } = this.state;
    fetch(`${instaAPI}?page=${offset}&limit=${LIMIT}`)
      .then((res) => res.json())
      .then((res) => {
        this.setState({
          posts: res.posts,
        });
      });
  }

컴디마로 첫 fetch 호출 시에도 마찬가지로 백과 맞춘 fetch주소를 걸어주고 posts에 해당 데이터를 넣어준다.


  render() {
    const { posts, loading } = this.state;

    return (
      <div className="InstaPage">
        <div className="instaTitle">
          <p>CONVERSE COMMUNITY</p>
        </div>
        <div className="imgContainer">
          <InstaList posts={posts} />
        </div>
        <div className="viewMoreBox">
          <button type="text" onClick={this.clickViewMore}>
            더보기
          </button>
        </div>
        <div className={`loadingModal ${loading ? "" : "hidden"}`}>
          <img src={gif} alt="preloader gif" />
        </div>
        ;
      </div>
    );
  }
}

export default InstaPage;

마치며

인스타그램은 한번 클로닝을 해봤던 것으로 나름 수월할 것을 생각했는데... 기능 하나 하나가 나에게 큰 도전이었다. 그래서 가장 애착이 가는 페이지이자 기능의 모음이다.

  • 인스타그램 호버기능 (검은 화면에 해당 박스에 맞는 인덱스 출력)
  • 인스타그램 모달창 (해당 박스에 맞는 데이터 프로필, 텍스트, 이미지 출력)
  • 모달창에서 다음 이전 버튼 기능 구현 (해당 인덱스 상단 컴포넌트 전달 후 그 인덱스에 맞는 데이터 나오도록 설정)
  • 모달창에서 해당 창 제외 바깥 화면(검은화면) 클릭 시 모달창 close기능 (해당 className 상단 컴포넌트 전달후 그게 맞다면 modalState값 변경, 모달창 클로즈 설정)
  • 더보기 기능 누를 시 fetch함수 작동 8개의 데이터만 더 불러와 출력
  • 더보기 기능 누를 시 데이터 불러올 동안만 로딩창 출력되도록 설정

나에겐 컨버스 클론 프로젝트라 읽고 인스타 기능 프로젝트라고 쓸정도로 도전의 연속이었지만 그 과정에서 react의 state과 props로 데이터를 이동하는 플로우를 익힐 수 있는 소중한 기회였다.

0개의 댓글