bang-gui/blog
나의 리액트 페이지. Contribute to bang-gui/blog development by creating an account on GitHub.
github.com
API를 작성하려면 URL지정에 신경 써야 한다.
현재 우리는 아래의 url 중에 post만을 구현하였다.
종류 | 기능 |
POST /posts | 포스트 작성 |
GET /posts | 포스트 목록 조회 |
GET /posts/:id | 특정 포스트 조회 |
DELETE /posts/:id | 특정 포스트 삭제 |
PATCH /post/:id | 특정 포스트 업데이트 |
POST /posts/:id/comments | 특정 포스트에 댓글 등록 |
GET /posts/:id/comments | 특정 포스트의 댓글 목록 조회 |
DELETE /posts/:id/comments/:commentsId | 특정 포스트에 특정 댓글 삭제 |
정말 감사하게도 댓글 기능을 구현하기 위한 URL을 책에서 알려준다.
위의 표대로 댓글을 위한 라우터를 먼저 만들어 보자.
import Router from 'koa-router';
import comments from '../comment';
import * as postsCtrl from './posts.ctrl';
import checkLoggedIn from '../../lib/checkLoggedIn';
const posts = new Router();
posts.get('/', postsCtrl.list);
posts.post('/', checkLoggedIn, postsCtrl.write);
const post = new Router(); // /api/posts/:id
post.get('/', postsCtrl.read);
post.delete('/', checkLoggedIn, postsCtrl.checkOwnPost, postsCtrl.remove);
post.patch('/', checkLoggedIn, postsCtrl.checkOwnPost, postsCtrl.update);
post.use('/comments',comments.routes()); //:id가 붙어있는 포스트에만 적용한다.
posts.use('/:id', postsCtrl.getPostById, post.routes());
export default posts;
import Router from 'koa-router';
const comments = new Router();
comments.post('/',ctx =>{
ctx.body = '댓글 포스트'
});
comments.get('/',ctx =>{
ctx.body = '댓글 겟'
});
comments.delete('/:commentsId',ctx =>{
ctx.body = '댓글 델리트'
})
export default comments;
포스트맨으로 시험해보았다. 잘 동작한다.
라우트 경로는 잘 지정했다.
글쓰기 기능을 시험하려면 인풋이 마련되어야 한다.
포스트 뷰어 하단에 댓글을 작성할 수 있는 인풋과 버튼을 만들어 보겠다.
전체 구성은 그림과 같다
컨테이너로 코멘트 뷰어를 감싸고 데이터와 액션들을 마련할 것이다.
import { createAction, handleActions } from 'redux-actions';
const CHANGE_INPUT = 'comments/CHANGE_INPUT';
export const changeInput = createAction(CHANGE_INPUT, input => input);
const initialState = {
input: '',
};
const comments = handleActions(
{
[CHANGE_INPUT]: (state, { payload: input }) => {
console.log(input);
return {
...state,
input: input,
};
}
},
initialState,
);
export default comments;
아주 간단한 리덕스 모듈을 먼저 작성했다.
리덕스를 적용시키는 것은 책에 잘 나와있으니 책을 참고하길 바란다.
import React, { useCallback } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { changeInput } from '../../modules/comments';
import CommentsViewer from '../../components/comments/CommentsViewer';
const CommentsViewerContainer = () => {
const input = useSelector((state) => state.comments.input);
const dispatch = useDispatch();
const onChangeCommentInput = useCallback(input =>
dispatch(changeInput(input)),
[dispatch]
);
return (
<CommentsViewer
onChangeCommentInput={onChangeCommentInput}
input={input}
/>
);
};
export default CommentsViewerContainer;
컨테이너를 마련하고...
import React from 'react';
import styled from 'styled-components';
// import palette from '../../lib/styles/palette';
import Responsive from '../common/Responsive';
import CommentInput from '../comments/CommentInput';
import Button from '../../components/common/Button';
const CommentsViewerBlock = styled(Responsive)`
margin-top: 4rem;
`;
const CommentButtonBlock = styled.div`
margin-top: 1rem;
display: flex;
justify-content: flex-end;
`;
const CommentsViewer = ({ onChangeCommentInput, input }) => {
return (
<CommentsViewerBlock>
<CommentInput onChangeCommentInput={onChangeCommentInput} input={input} />
<CommentButtonBlock>
<Button>댓글 작성</Button>
</CommentButtonBlock>
</CommentsViewerBlock>
);
};
export default CommentsViewer;
뷰어를 만들고...
import React from 'react';
import styled from 'styled-components';
import TextareaAutosize from 'react-autosize-textarea';
const StyledCommentInput = styled.input`
width: 100%;
border: none;
outline: none;
font-size: 1rem;
padding: 1rem;
border: 1px solid gray;
border-radius: 4px;
color: gray;
display: block;
line-height: 1.5;
`;
const CommentInput = ( {onChangeCommentInput, input }) => {
const onChange = (e) => onChangeCommentInput(e.target.value);
return (
<>
<hr />
<StyledCommentInput
value={input}
onChange={onChange}
placeholder="댓글을 입력하세요"
rows={2}
maxRows={20}
/>
</>
);
};
export default CommentInput;
그리고 인풋을 만들었다.
그리고 마지막으로 컨테이너를 postViewer 컴포넌트 안에 위치해주어야 한다.
import React from 'react';
import styled from 'styled-components';
import palette from '../../lib/styles/palette';
import Responsive from '../common/Responsive';
import SubInfo from '../common/SubInfo';
import Tags from '../common/Tags';
import CommentsViewerContainer from '../../containers/comments/CommentsViewerContainer'
import { Helmet } from 'react-helmet-async';
const PostViewerBlock = styled(Responsive)`
margin-top: 4rem;
`;
const PostHead = styled.div`
border-bottom: 1px solid ${palette.gray[2]};
padding-bottom: 3rem;
margin-bottom: 3rem;
h1 {
font-size: 3rem;
line-height: 1.5;
margin: 0;
}
`;
const PostContent = styled.div`
font-size: 1.3125rem;
color: ${palette.gray[8]};
`;
const PostViewer = ({ post, error, loading, actionButtons }) => {
// 에러 발생 시
if (error) {
if (error.response && error.response.status === 404) {
return <PostViewerBlock>존재하지 않는 포스트입니다.</PostViewerBlock>;
}
return <PostViewerBlock>오류 발생!</PostViewerBlock>;
}
// 로딩중이거나, 아직 포스트 데이터가 없을 시
if (loading || !post) {
return null;
}
const { title, body, author, publishedDate, tags } = post;
return (
<PostViewerBlock>
<Helmet>
<title>{title} - Received King</title>
</Helmet>
<PostHead>
<h1>{title}</h1>
<SubInfo
username={author.username}
publishedDate={publishedDate}
hasMarginTop
/>
<Tags tags={tags} />
</PostHead>
{actionButtons}
<PostContent dangerouslySetInnerHTML={{ __html: body }} />
<CommentsViewerContainer/> // 여기에다 요로콤 추가해라
</PostViewerBlock>
);
};
export default PostViewer;
자... 이제 뭘 해야 하나...
아 이제 쓰기 API를 만들어보자... 젠장...
나는 댓글의 내용을 body라고 설정했다.
lib/api 아래에 comments.js를 만들자
import client from './client';
export const writeComments = ({ id, body }) =>
client.post(`/api/posts/${id}/comments`, { body });
조금씩 간단하게, 쓰기만 먼저 구현해보자.
이제 위의 api를 사용하기 위한 리덕스 액션과 사가를 준비해보자...
이것만 해도 어마무시하게 복잡한 느낌이 든다.
'웹' 카테고리의 다른 글
댓글 읽기 요청 보내기 (0) | 2020.11.18 |
---|---|
리덕스로 댓글 쓰기 요청 보내기 (0) | 2020.11.18 |
DB를 위한 댓글 스키마 생성하기 (0) | 2020.11.16 |
'리액트를 다루는 기술' 댓글기능 추가해보기 2. 아웃라인 (0) | 2020.11.16 |