Next
useQuery 사용한 api요청
나를 너무나도 괴롭혔던 것들 메모하기
1
2
3
4
5
6
7
8
9
10
const router = useRouter();
const {id} = router.query;
function fetchPost(id){
const response = await api.get(`/post/${id}`);
return response.data;
};
const {isLoading, data, } = useQuery(["post", id], fetchPost(id));
- 기억에 의존하기에 정확하지 않을 수 있지만 흐름을 이해해본다.
- 본인이 하려던 것
- 페이지 번호에 해당하는 쿼리를 찾아,
api
요청을 보내 게시글을 찾는다.
- 페이지 번호에 해당하는 쿼리를 찾아,
- 문제
- 렌더링 될 때
query
를 파악하기도 전에,api
요청이 먼저 가게 되어,undefined
로 요청이 간다.
- 렌더링 될 때
- 해결
useEffect
를 사용하여router
가 변할 때마다id
를 받아와 새롭게 요청을 한다.router
도 변하기 때문에 이를 감지할 수 있어야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const [apiNumber, setApiNumber] = useState<number|undefined>();
const router = useRouter();
useEffect(() => {
const id = Number(router.query.id);
setApiNumber(id);
}, [id])
function fetchPost(apiNumber){
const reponse = await api.get(`/post/${apiNumber}`);
return response.data;
}
const {isLoading, data, } = useQuery(["post", apiNumber], fetchPost(apiNumber));
custom hook에서 data 꺼내 사용하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
export interface PostType {
postNumber: number;
author: string;
title: string;
body: string;
date: string;
views: number;
likes: number;
comments: CommentType[];
}
export function usePostDetail(id: number) {
const fetchPost = async (): Promise<PostType> => {
const response = await api.get<PostType>(`/post/${id}`);
return response.data;
};
return useQuery<PostType>(['post', id], fetchPost, {
staleTime: 2000,
});
}
export default function index() {
const [postNum, setPostNum] = useState<number | undefined>();
const router = useRouter();
useEffect(() => {
const id = Number(router.query.id);
setPostNum(id);
}, [router]);
return (
<Container>
{postNum && <PostDetail id={postNum} />}
<Login />
</Container>
);
}
export default function PostDetail({ id }: { id: number }) {
const queryResult = usePostDetail(id);
// const {data} = usePostDetail(id); => error
console.log(queryResult);
if (queryResult.isLoading) {
return <div>Loading...</div>;
}
if (queryResult.isError) {
const error = queryResult.error as Error;
return <div>Error: {error.message}</div>;
}
if (!queryResult.data) {
return <div>No data available</div>;
}
const data: PostType = queryResult.data;
console.log(data);
return <Container></Container>;
}
// data
{
postNumber: 123,
author: "choigirang",
title: "안녕하세요",
body: "<p>첫 글입니다.</p>",
date: "2023-08-17",
views: 0,
likes: 0,
comments: [];
}
- 위의 게시글 찾기를
custom hook
을 사용하여 페이지 번호를 파악하고 번호와 일치하는 게시글을 받아오도록 한다. query
의data
를 바로 사용하려고 했을 때 문제가 발생했는데, 이는useQuery
안에는Loading, data, Error
등의 여러가지 메서드가 있기 때문에 이 중data
를 특정해서 추출해야 한다.
fetch 등의 함수
- 컴포넌트 안에
fetch
함수를 사용했지만, 이는 컴포넌트가 렌더링 될 때마다 함수도 새로이 사용되기 때문에 낭비다. - 이럴 경우 꼭 컴포넌트와 분리하여 사용하거나,
custom Hook
을 만들어 사용하자.
Draft.js
- 에디터 작성을 위한 여러가지 라이브러리 중
Draft.js
를 써보기로 했다. quil, Toast Ui
등 여러가지 라이브러리가 있었지만, 라이브러리install
횟수가 가장 많은 것을 택했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import React, { useState, useEffect } from "react";
import { ContentState, convertToRaw, EditorState } from "draft-js";
import { Editor } from "react-draft-wysiwyg";
import draftToHtml from "draftjs-to-html";
import "react-draft-wysiwyg/dist/react-draft-wysiwyg.css";
import styled from "styled-components";
import htmlToDraft from "html-to-draftjs";
interface IEditor {
htmlStr: string;
setHtmlStr: React.Dispatch<React.SetStateAction<string>>;
}
export default function PostEditor({ htmlStr, setHtmlStr }: IEditor) {
const [editorState, setEditorState] =
useState < EditorState > (() => EditorState.createEmpty());
useEffect(() => {
const blockFromHtml = htmlToDraft(htmlStr);
if (blockFromHtml) {
const { contentBlocks, entityMap } = blockFromHtml;
const contentState = ContentState.createFromBlockArray(
contentBlocks,
entityMap
);
const editorState = EditorState.createWithContent(contentState);
setEditorState(editorState);
}
}, []);
const onEditorStateChange = (editorState: EditorState) => {
setEditorState(editorState);
setHtmlStr(draftToHtml(convertToRaw(editorState.getCurrentContent())));
};
const toolbar = {
list: { inDropdown: true },
textAlign: { inDropdown: true },
link: { inDropdown: true },
history: { inDropdown: true },
image: { uploadCallback: uploadCallback },
};
const localization = {
locale: "ko",
};
return (
<>
<Container>
<Editor
editorClassName="editor"
toolbarClassName="toolbar"
toolbar={toolbar}
placeholder="내용을 입력하세요"
localization={localization}
editorState={editorState}
onEditorStateChange={onEditorStateChange}
/>
</Container>
</>
);
}
- 상당히 복잡하고 아직 다 이해하진 못 했지만 대략적으로,
draft.js
를 원활히 사용하기 위해 기본적으로 설치해줘야 하는 것들이 많다.draft.js
draftjs-to-html
html-to-draftjs
react-draft-wysiwyg
- 위 항목들을 다 설치해야 되고
typeScript
를 사용할 경우, 또 타입마다 설치해줘야 한다. - 코드의 대략적인 설명은, 에디터에 입력되는, 혹은 에디터를 사용하여 부여되는 효과 별로
markdown
으로 변환된다. - 변환된 문자열을 보내고 저장해두었다가, 불러올 때는 다시 마크다운을 문자열로 변환하여 사용한다.
- 여러가지 옵션이 있기 때문에 커스텀이 자유롭고, 본인에게 필요한 기능과 옵션을 십분 활용하기로 하자. [https://jforj.tistory.com/213]