13-9. 덧글 끊어서 5개씩 더 보기

컴포넌트에 limit 이라는 state 를 정의하고, handleReadMore 라는 메소드를 만들어서 호출이 될 때마다 limit 의 값에 5를 더하도록 합니다.

그리고, ReadMore 컴포넌트를 스타일링하여 이 컴포넌트가 클릭 됐을 때 handleReadMore 를 호출하며, 이 컴포넌트는 덧글 갯수 - limit 이 1 이상일때만 보여지도록 설정하세요.

src/components/Shared/PostList/CommentList.js

import React, { Component } from 'react';
import styled from 'styled-components';
import oc from 'open-color';
import Comment from './Comment';

const CommentListwrapper = styled.div`
    margin-top: 0.75rem;
`;

const ReadMore = styled.div`
    color: ${oc.gray[6]};
    font-size: 0.9rem;
    text-align: center;
    cursor: pointer;

    &:hover {
        color: ${oc.cyan[6]};
        font-weight: 500;
    }
`

class CommentList extends Component {

    state = {
        limit: 5
    }

    handleReadMore = () => {
        this.setState({
            limit: this.state.limit + 10
        });
    }

    render() {

        const { comments } = this.props;
        if (comments.size === 0) return null; // 덧글이 비어있다면 아무것도 렌더링하지 않습니다.
        const { limit } = this.state;
        const { handleReadMore } = this;

        const commentList = comments.slice(0, limit).map(
            (comment) => (
                <Comment {...comment.toJS()} key={comment.get('_id')}/>
            )
        );

        return (
            <CommentListwrapper>
                {commentList}
                { limit < comments.size && <ReadMore onClick={handleReadMore}>{comments.size - limit}개 더 보기</ReadMore> }
            </CommentListwrapper>
        );
    }
}

export default CommentList;

여기까지 작업을 하고 나면, 더보기 버튼이 생겨서 덧글을 끊어서 볼 수 있게 됩니다. 하지만, 이건 컴포넌트의 로컬 업데이트만 이뤄지기 때문에 Masonry 의 레이아웃이 이뤄지지 않습니다.

여기서, 만약에 Masonry 의 레이아웃 함수를 실행하려면 조금 구조가 복잡합니다.

일반적인 흐름으로는, PostListContainer 에서 레이아웃 메소드 생성 → PostList → CommentBlockContainer → CommentBlock → CommentList 의 순서로 전달을 해주어야합니다. 물론, 이렇게 직접 전달을 해도 되긴 하지만, 과정이 조금 복잡하기도 하고, 너무 많은 컴포넌트를 거쳐서 전달이 되어 불편합니다.

이런 경우에, 유용하게 사용 될 수 있는것이 바로 Higher Order Component 입니다 (이하 HoC 라고 부르겠습니다.)

HoC 는 간단하게 이해하자면, 리액트 컴포넌트를 확장시켜주는 역할이라고 이해하시면 되겠습니다. 예를들어서, 우리가 redux 상태들을 컴포넌트에 연결시켜줄때, connect 라는 함수를 사용하지요? 이것이 바로 HoC 의 일종입니다. 이 과정에서는, 컴포넌트를 함수로 감싸주면서 컴포넌트에 특정 기능을 부여하여 새 컴포넌트를 만들어줍니다.

이번엔 우리가 여러 컴포넌트를 거치지 않고 더 간편하게 masonry 의 relayout 을 트리거 할 수 있도록 HoC 를 만들어서 구현을 해보겠습니다.

relayout 을 해주는 HoC 만들기

HoC 는 컴포넌트 클래스를 파라미터로 받아오고, 파라미터로 받아온 컴포넌트를 렌더링 합니다. 그리고 여기서, 우리가 특정 props 를 임의로 주입을 할 수 있습니다. 여기서 주의 하실 점은, 컴포넌트를 렌더링 할 때 {...this.props} 를 추가하여, 이 컴포넌트가 받아야 할 props 들을 그대로 전달해줘야 한다는 점 입니다.

이 HoC 에서는 relayout 함수를 onRelayout props 로 전달하도록 설정을 했으며, relayout 함수는 setRelayoutHandler 함수를 통하여 설정을 할 수 있게 작성하였습니다.

import React, { Component } from 'react';

// 기본적으로는 설정되지 않았다는 오류 메시지를 보여주고, setRelayoutHandler 를 통해서 설정을 해주어야합니다.
let relayout = () => {
    console.error(new Error('relayout is not defined'));
}

// 함수를 받아와서 relayout 에 설정합니다
export const setRelayoutHandler = (handler) => {
    relayout = handler;
};

export default function withRelayout(WrappedComponent){
    // 함수 내부에서 컴포넌트를 정의합니다
    return class extends React.Component {
        render() {
            return (
                <WrappedComponent onRelayout={relayout} {...this.props}/>
            );
        }
    }
}

PostListContainer 에서 setRelayoutHandler 사용하기

PostListContainer 컴포넌트에서, handleRelayout 이라는 함수를 만들고, 컴포넌트가 마운트 됐을 때, setRelayoutHandler 를 통하여 handleRelayout 을 HoC 에서 relayout 함수로 사용 할 수있도록 코드를 작성하세요.

src/containers/Shared/PostListContainer.js

(...)
import { setRelayoutHandler } from 'lib/withRelayout';

class PostListContainer extends Component {
    (...)

    handleRelayout = () => {
        setTimeout(() => this.masonry.masonry.layout(), 0);
    }

    componentDidMount() {
        // 컴포넌트가 마운트 됐을 때 호출 합니다.
        this.load();
        window.addEventListener('scroll', this.handleScroll);
        setRelayoutHandler(this.handleRelayout);
    }

    (...)
}

(...)

CommentList 에서 HoC 사용하기

withRelayout 를 불러와서, CommentList 를 내보낼 때 감싸주면, onRelayout 함수를 props 로 받게됩니다. 이 함수를, handleReadMore 에서 호출하게 하면, 모든게 해결됩니다!

(...)

import withRelayout from 'lib/withRelayout';

(...)

class CommentList extends Component {

    state = {
        limit: 5
    }

    handleReadMore = () => {
        this.setState({
            limit: this.state.limit + 10
        });
        this.props.onRelayout();
    }

    (...)
}

export default withRelayout(CommentList);

만약에 HoC 가 없었더라면 5개의 컴포넌트를 거쳐서 전달해줘야 하는 props 를, HoC 를 통하여 중간자 역할을 하게끔 하여 지름길을 통해 간편하게 전달을 해주었습니다.

여기까지 코드를 작성하고 나면, 덧글 더보기가 정상적으로 작동하게 됩니다.

results matching ""

    No results matching ""