6. 포스트 읽기
우리가 앞으로 구현 할 마지막 페이지입니다. 한개의 포스트를 읽어오는 페이지를 만들어봅시다.
UI 준비하기
PostViewer 라는 컴포넌트를 만들어서 제목과 날짜, 내용을 보여주겠습니다.
이번에 만들 컴포넌트는 posts 라는 분류로 저장합니다.
components/posts/PostViewer.js
import React from 'react';
import './PostViewer.scss';
import { formatDate } from '../../lib/common';
const PostViewer = () => {
return (
<div className="PostViewer">
<h1 className="title">title</h1>
<div className="meta">
<span className="username">
by <b>username</b>
</span>
<span className="separator">·</span>
<span className="date">
{formatDate(Date.now() - 1000 * 60 * 60 * 4)}
</span>
</div>
<div
className="body"
dangerouslySetInnerHTML={{
__html: '<p>Hello <b>World!</b<</p>'
}}
/>
</div>
);
};
export default PostViewer;
components/posts/PostViewer.scss
.PostViewer {
margin-top: 5rem;
margin-bottom: 2.5rem;
.title {
color: $oc-gray-9;
font-size: 3rem;
margin-bottom: 0.5rem;
}
.meta {
color: $oc-gray-6;
font-style: italic;
.separator {
margin-left: 0.25rem;
margin-right: 0.25rem;
}
}
.body {
margin-top: 4rem;
font-size: 1.125rem;
color: $oc-gray-7;
line-height: 1.5;
blockquote {
padding-left: 1rem;
border-left: 4px solid $oc-gray-9;
}
}
}
이 컴포넌트를 다 만드셨으면, PostPage 에서 렌더링을 해줍시다. HeaderContainer 도 함께 보여주세요.
pages/PostPage.js
import React from 'react';
import HeaderContainer from '../containers/base/HeaderContainer';
import PostViewer from '../components/posts/PostViewer';
import Responsive from '../components/base/Responsive';
/**
* 포스트 읽는 페이지
*/
const PostPage = () => {
return (
<>
<HeaderContainer />
<Responsive>
<PostViewer />
</Responsive>
</>
);
};
export default PostPage;
포스트를 열었을 때 위와 같은 화면이 잘 나타났나요?
API 연동하기
이번에 API 를 연동 할 때에는 이전에 우리가 PostList 를 구현 할 때 api/posts.js 에 미리 만들었었던 read 함수를 사용합니다.
export const read = id => client.get(`/api/posts/${id}`);
여기서는 리덕스 모듈을 새로 만들지는말고 기존에 만들었던 posts 모듈을 조금 수정해주세요.
modules/posts.js
import { handleActions } from 'redux-actions';
import createPromiseThunk from '../lib/createPromiseThunk';
import * as postsAPI from '../lib/api/posts';
const LIST_POSTS = 'posts/LIST_POSTS';
const LIST_POSTS_SUCCESS = 'posts/LIST_POSTS_SUCCESS';
const READ_POST = 'posts/READ_POST';
const READ_POST_PENDING = 'posts/READ_POST_PENDING';
const READ_POST_SUCCESS = 'posts/READ_POST_SUCCESS';
export const listPosts = createPromiseThunk(LIST_POSTS, postsAPI.listPosts);
export const readPost = createPromiseThunk(READ_POST, postsAPI.read);
const initialState = {
list: null
};
export default handleActions(
{
[LIST_POSTS_SUCCESS]: (state, { payload }) => ({
...state,
list: payload.data
}),
[READ_POST_PENDING]: state => ({ ...state, post: null }), // 포스트 불러올 때 기존 내용 초기화해줌
[READ_POST_SUCCESS]: (state, { payload }) => ({
...state,
post: payload.data
})
},
initialState
);
이제 PostViewerContainer 를 만듭시다.
containers/posts/PostViewerContainer.js
import React, { Component } from 'react';
import PostViewer from '../../components/posts/PostViewer';
import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import { readPost } from '../../modules/posts';
class PostViewerContainer extends Component {
initialize = async () => {
const { match, readPost } = this.props;
const { postId } = match.params;
try {
await readPost(postId);
} catch (e) {
console.log(e);
}
};
componentDidMount() {
this.initialize();
}
render() {
const { post } = this.props;
if (!post) return null;
return (
<PostViewer
title={post.title}
body={post.body}
date={post.created_at}
username={post.user.username}
/>
);
}
}
export default withRouter(
connect(
state => ({
post: state.posts.post
}),
{
readPost
}
)(PostViewerContainer)
);
그리고, PostViewer 에서 전달받은 props 를 렌더링해주세요.
components/posts/PostViewer.js
import React from 'react';
import './PostViewer.scss';
import { formatDate } from '../../lib/common';
const PostViewer = ({ title, username, date, body }) => {
return (
<div className="PostViewer">
<h1 className="title">{title}</h1>
<div className="meta">
<span className="username">
by <b>{username}</b>
</span>
<span className="separator">·</span>
<span className="date">{formatDate(date)}</span>
</div>
<div
className="body"
dangerouslySetInnerHTML={{
__html: body
}}
/>
</div>
);
};
export default PostViewer;
마지막으로, PostPage 에서 PostViewer 를 PostViewerContainer 로 대체하세요.
pages/PostPage.js
import React from 'react';
import HeaderContainer from '../containers/base/HeaderContainer';
import Responsive from '../components/base/Responsive';
import PostViewerContainer from '../containers/posts/PostViewerContainer';
/**
* 포스트 읽는 페이지
*/
const PostPage = () => {
return (
<>
<HeaderContainer />
<Responsive>
<PostViewerContainer />
</Responsive>
</>
);
};
export default PostPage;
실제 포스트 내용이 잘 보여지나요?