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">&middot;</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">&middot;</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;

실제 포스트 내용이 잘 보여지나요?

results matching ""

    No results matching ""