forked from dalping/react-devfolio-board
-
Notifications
You must be signed in to change notification settings - Fork 0
화면 구성 및 주요 기능 설명
Lee Min Wook edited this page Feb 28, 2022
·
17 revisions
- 메인 페이지
- 게시글 상세 페이지
- 게시글 등록 페이지
- 검색 페이지
- 벨로그의 무한스크롤 기능은 Intersection Observer API를 이용하였습니다. Intersection Observer가 관찰하고 있는 요소에 사용자가 접근했다면 옵저버에 구독된 이벤트를 발생시켜 서버에서 추가로 데이터를 가져오게 됩니다.
const observer = node => {
if (node === null || lastPageCheck.current === true) return;
if (observerRef.current) observerRef.current.disconnect();
// 타겟이된 노드에 접근을 했다면 옵저버가 구독된 이벤트를 실행시켜준다.
observerRef.current = new IntersectionObserver(([entry], observer) => {
// 타겟이 접근을 했는지 감지한다.
if (entry.isIntersecting) {
// 서버에게 자주 호출하는 걸 방지 하기 위해 디바운스
if (timer) {
return clearTimeout(timer);
}
// ... 생략
timer = setTimeout(
call(async () => {
// 요소에 접근했다면 서버에서 데이트를 추가로 받아온다.
const postsResponse = await posts.get(
currentLimit,
currentPage + 1
);
const { results, page, totalPages, limit } = postsResponse.data;
const newPosts = await comments.getComments(results);
return {
posts: [...newPosts],
state: { page, totalPages, limit },
};
}),
REQUEST_DELAY
);
}
});
observerRef.current.observe(node);
};
- 짫은 시간에 서버에 데이터를 여러번 요청하는걸 방지하기위해 디바운스를 통해 제어하였습니다. 요소에 접근하여 1초 동안 새로운 접근이 없어야 서버에서 데이터를 가져옵니다.
let timer;
// 1초 동안 새로운 접근이없어야 요청을한다.
const REQUEST_DELAY = 1000;
// ... 생략
timer = setTimeout(
call(async () => {
// 요소에 접근했다면 서버에서 데이트를 추가로 받아온다.
const postsResponse = await posts.get(
currentLimit,
currentPage + 1
);
// ... 생략
}),
REQUEST_DELAY
);
- 사용자에게 게시글을 추가로 가져온다는 경험을 주기 위해 loading 이미지를 사용하였습니다. loading 컴포넌트는 재사용이 가능하도록 HOC로 만들어서 다른 컴포넌트도 이용할 수 있도록 했습니다.
import React from 'react';
import Loading from '@/Components/common/Loading';
const withLoading = Component => {
return function component({ loading, ...rest }) {
return (
<>
<Loading {...{ loading }} />
<Component {...rest} />
</>
);
};
};
export default withLoading;
// hoc 사용
export default withLayout(MainPage);
- 임시저장 기능을 구현하기 위해 리덕스를 이용하였습니다. 리덕스 스토어에 저장된 글이 있다면 임시 저장된 글을 가져와 보여줍니다.
useEffect(() => {
if (transientStorageState.data) {
const { data } = transientStorageState;
setForm(prev => ({
...prev,
...data,
tags: new Set([...data.tags]),
}));
}
}, [transientStorageState]);
- 게시글 작성을 위해 CK에디터를 이용하였습니다.
<Body>
<CKEditor editor={ClassicEditor} config={editorConfiguration} {...rest} />
</Body>
- 게시글의 섬네일 이미지는 S3에 저장을 하며 프론트에서 바로 올릴 수 있도록 AWS SDK를 이용하여 구현하였습니다.
const s3Upload = file => {
AWS.config.update({
region: 'ap-northeast-2', // 버킷이 존재하는 리전을 문자열로 입력합니다. (Ex. "ap-northeast-2")
credentials: new AWS.CognitoIdentityCredentials({
// API_KEY는 웹팩에서 설정
IdentityPoolId: API_KEY, // cognito 인증 풀에서 받아온 키를 문자열로 입력합니다. (Ex. "ap-northeast-2...")
}),
});
const upload = new AWS.S3.ManagedUpload({
params: {
Bucket: BUCKET,
Key: `file/${file.name}`,
Body: file,
},
});
return upload;
};
- 검색은 제목, 태그, 내용 3가지 필터를 통해서 검색할 수 있습니다. 사용자가 글을 작성하면 자동으로 서버로 요청해서 실시간으로 검색 결과를 보여줍니다.
- 짧은 시간 서버로 요청을 제어하기 위해 디 바운스를 이용하였습니다.
timer = setTimeout(() => {
call(async () => {
setList(null);
const { value } = target;
let response;
if (keyWord === 'body') {
response = await postsByKeyWord(
keyWord,
encodeURIComponent(`<p>${value}</p>`)
);
} else {
response = await postsByKeyWord(keyWord, encodeURIComponent(value));
}
const { results, limit, page, totalPages, totalResults } =
response.data;
const newPosts = await getComments(results);
return {
keyWord,
value,
posts: [...newPosts],
state: { limit, page, totalPages, totalResults },
};
});
}, 1000);