10-1. PostList 생성 및 Masonry 테스팅
디자인 구상
이번 섹션에서는 본격적으로 포스트 카드를 디자인 하기전에, Masonry 레이아웃을 테스팅을 해보도록 하겠습니다.
우선, react-masonry-component
를 설치합니다.
그 다음엔, 포스트 카드의 틀을 만들겠습니다.
masonry 를 사용할때는, 사이즈 조정이 중요한데요, 각 화면에서 어떻게 보여줄 지 먼저 알아보겠습니다.
- 데스크탑: 한 줄에 3개를 보여줌
- 태블릿: 한 줄에 2개를 보여줌
- 모바일: 한 줄에 1개를 보여줌
그리고, 각 카드끼리는 16px 의 여백이 있습니다. 여백의 경우엔 상하 여백은 margin-bottom
으로 설정하며, 좌우 여백은 masonry 에서 gutter
라는 값으로 설정을 해줍니다.
데스크탑일때는,
[] [] []
이런식으로 카드와 카드 사이 여백이 두번 들어가게 되기 때문에 전체 너비에서 (16px * 2) 를 뺸 다음에 3으로 나눈 값: width: calc((100% - 32px) / 3);
이 너비가 되며,
태블릿의 경우엔,
[] []
이와 같이 카드와 카드 사이 여백이 한번 있으므로 전체 너비에서 16px 를 빼고 2로 나눈 값인 width: calc((100% - 16px) / 2);
가 너비가 됩니다.
마지막으로 모바일의 경우엔 한 줄에 하나만 보여주기 때문에 100% 로 하면 됩니다.
Post 컴포넌트 만들기
그러면, 위의 정보에 따라서 카드 사이즈를 설정하여 컴포넌트를 생성해보겠습니다.
우리가 앞으로 만들 PostList, 그리고 이와 관련된 컴포넌트는 components/Shared 디렉토리에 저장하도록 하겠습니다. 그 이유는, 홈에서도 사용이 되고, 유저 페이지에서도 사용이 되기 때문입니다.
src/components/Shared/PostList/Post.js
import React from 'react';
import styled from 'styled-components';
import oc from 'open-color';
import PropTypes from 'prop-types';
import { media, shadow } from 'lib/styleUtils';
const Wrapper = styled.div`
width: calc((100% - 32px) / 3);
${media.desktop`
width: calc((100% - 16px) / 2);
`}
${media.tablet`
width: 100%;
`}
height: 400px;
margin-bottom: 1rem;
background: white;
${shadow(1)}
`;
const Post = () => (
<Wrapper>
</Wrapper>
);
export default Post;
포스트의 내용은 일단 비워두고 나중에 구현하도록 하겠습니다.
PostList 컴포넌트 만들기
이제 여러개의 Post 를 감싸줄 PostList 를 만들겠습니다. 이 컴포넌트에서는 position: relative
속성을 주는것이 중요합니다. 그 이유는 Post 컴포넌트의 사이즈가 이 컴포넌트의 너비와 비례하여 만들어지기 때문입니다.
PostList 내부에서, Masonry
컴포넌트를 불러와서 사용을 하게 되는데, 이 때 options
에 gutter
값을 설정하여 좌우 여백을 설정합니다.
그리고, 해당 컴포넌트의 자식 컴포넌트들로 정렬할 컴포넌트인 Post 컴포넌트를 여러개 렌더링을 해주면 Masonry 가 레이아웃을 처리해줍니다.
일단은, 아직 데이터를 불러오지 않았기 때문에, 여러개의 <Post/>
를 하드코딩하여 작성하도록 하겠습니다.
src/components/Shared/PostList/PostList.js
import React from 'react';
import styled from 'styled-components';
import Masonry from 'react-masonry-component';
import Post from './Post';
const Wrapper = styled.div`
position: relative;
margin-top: 1rem;
`;
const PostList = () => (
<Wrapper>
<Masonry options={{gutter: 16}}>
<Post/>
<Post/>
<Post/>
<Post/>
<Post/>
<Post/>
<Post/>
<Post/>
<Post/>
<Post/>
<Post/>
</Masonry>
</Wrapper>
);
export default PostList;
이 다음엔 PostList 컴포넌트를 기본으로 내보내주는 인덱스파일을 작성합니다.
src/components/Shared/PostList/index.js
export { default } from './PostList';
이제 PostListContainer 컴포넌트를 생성해서 PostList 를 렌더링하고, 해당 컴포넌트를 Home 에서 보여주겠습니다.
src/containers/Shared/PostList/PostListContainer.js
import React, { Component } from 'react';
import PostList from 'components/Shared/PostList';
class PostListContainer extends Component {
render() {
return (
<PostList/>
);
}
}
export default PostListContainer;
이 파일도 인덱스를 만들어줍니다.
src/components/Shared/PostList/index.js
export { default as PostListContainer } from './PostListContainer';
src/pages/Home.js
import React, { Component } from 'react';
import PageWrapper from 'components/Base/PageWrapper';
import { WritePostContainer } from 'containers/Home';
import { PostListContainer } from 'containers/Shared/PostList';
class Home extends Component {
render() {
return (
<PageWrapper>
<WritePostContainer/>
<PostListContainer/>
</PageWrapper>
);
}
}
export default Home;
이렇게 PostList 를 보여주었을때 다음과 같이 나타나면 정상입니다:
이 때 문제점이 한가지 발생하는데, 헤더에 z-index 값을 주지 않아서 카드가 헤더를 가리는 현상이 나타나게 됩니다. 헤더의 Positioner 부분에 z-index 값을 설정하세요.
src/components/Base/Header/Heaader.js
- Positioner
const Positioner = styled.div`
display: flex;
flex-direction: column;
position: fixed;
width: 100%;
top: 0px;
${shadow(1)}
z-index: 20;
`;