
오늘 배운 것
- 미니 해커톤 : 나만의 아고라 스테이츠 만들기 완성! + 깃헙 페이지 배포
My Agora States
kimploo / 2022-04-22T14:08:33Z
hyejj19.github.io
- 페이지네이션/ 로컬 스토리지 저장기능 구현
새롭게 알게된 것
- Date 객체의 toLocaleString() 메서드로 날짜와 시간 포맷 다듬어서 출력하기 : 무식하게 getDate, getHours로 하나하나 정렬해 주었는데, 이 메서드를 쓰면 나름 예쁘게 다듬어준다.
new Date()
// Tue Jul 19 2022 20:07:57 GMT+0900 (한국 표준시)
new Date().toLocaleString()
// '2022. 7. 19. 오후 8:08:25'
// 다른 포맷의 날짜와 시간을 전달하여 호출해도 포맷을 정렬해줌
new Date("2022-05-16T02:09:52Z").toLocaleString()
// '2022. 5. 16. 오전 11:09:52'
로컬 스토리지 저장 구현 방법
- 마지막에 로컬 스토리지에 저장 되는 것 까지 확인했지만, 유저가 새로운 정보를 입력 후 submit을 할 때 기존 로컬스토리지의 사용자 데이터가 날라가는 현상이 있었다. 로컬 스토리지에 저장된 데이터를 submit 한 후 불러오는 과정에서 오류가 있었던 것 같은데, 고치다가 홍식님께서 레퍼런스를 남겨주셔서 문제점을 발견하고 고칠 수 있었다.
- 문제는 데이터를 저장하는 형식에 있었다. 로컬스토리지에 데이터를 저장할 때, 배열 안에 저장된 더미데이터 객체들과 사용자가 입력한 데이터를 배열로 묶지 않고 하나씩 키 값을 지정하여 로컬스토리지에 저장하려고 했었다. 그런데 이 때 키 값이 겹치면 안되고 또 키 값을 0으로 만들면 기존에 키 값이 0인 데이터가 업데이트 되어버리니 누적해서 저장할 수 없는 것이었다.
- 처음에는 로컬 스토리지에 저장되는 키 값을 배열의 인덱스로 하려고 했는데, 그러면 배열에 먼저 unshift로 저장을 하고 배열을 다시 불러와 렌더링을 해주어야 했다. 여기까지는 되었는데, 앞서 언급했듯 submit을 누르면 새로고침 이전에 작성한 데이터가 다시 날라가고 처음부터 쌓여버리니 뭔가 데이터 형식도 맞지 않고 코드가 어디선가 꼬였던 것 같다.
// 로컬 스토리지의 데이터 불러오는 과정
// 1. 데이터를 담을 변수를 선언한다.
// 2. 로컬 스토리지에서 'agora...'를 키 값으로 하는 데이터를 불러온다.
// 3. 만약 데이터가 존재할 경우 data 변수안에 파싱하여 저장
// 4. 없다면 더미데이터를 slice 하여 저장.
// data에 배열 > 객체들 형태로 담기게 된다. (더미데이터와 동일하게 생겼음)
let data;
const dataFromLocalStorage = localStorage.getItem('agoraStatesDiscussions');
if (dataFromLocalStorage) {
data = JSON.parse(dataFromLocalStorage);
} else {
data = agoraStatesDiscussions.slice();
}
- 이렇게 코드를 작성하면 data 라는 배열에 전체 더미데이터 + (뒤에 코드가 나오겠지만) 사용자가 추가하는 데이터까지 배열에 담기게 된다. 로컬 스토리지가 비어있는 상태에서는 더미데이터를 data 변수에 담고, 그 data를 이용해 화면에 출력한다. 후에 사용자가 submit을 하면 사용자가 추가한 데이터가 배열에 담기고, 해당 배열이 로컬 스토리지에 저장된다.
// 사용자가 입력한 데이터 로컬스토리지 저장
// 해당 함수를 form 에 submit 이벤트 리스너에 전달해주면 된다.
const makeInputToQuestion = function (e) {
// ...코드 생략
// 1. obj 를 생성하여 data 배열에 추가.
data.unshift(obj);
// 2. data 배열 전체를 'agora...' 라는 키 이름으로, 문자열화하여 로컬 스토리지에 추가.
localStorage.setItem('agoraStatesDiscussions', JSON.stringify(data));
}

페이지네이션 구현 방법
- 페이지네이션 구현을 위해 함수를 크게 5가지 종류로 분류했다.
- 데이터를 DOM 으로 생성하는 함수
- 데이터를 화면에 렌더링 하는 함수
- 버튼 DOM 을 동적으로 생성하는 함수
- 버튼을 화면에 렌더링 하는 함수
- 버튼의 페이지이동 이벤트 핸들러와, 데이터 + 버튼 렌더링을 동시에 핸들링하는 함수
뭔가 아직도 머릿속에 딱! 정리가 되지는 않아서 쉽게 설명은 어렵겠지만.. 그냥 최대한 이해한대로 정리해보려고 함.
- 먼저 페이지네이션을 위해 데이터를 셋팅한다.
const numOfContent = data.length;
const maxContent = 8;
const maxButton = 5;
const maxPage = Math.ceil(numOfContent / maxContent);
let page = 1;
- 데이터를 DOM으로 생성하는 함수 : 코드가 너무 길어서 그냥 간략하게 줄이겠음..
이 함수에서는 obj 객체를 받아와서 DOM 으로 변환해준 뒤 그 li 를 리턴해주고 있다.
// 데이터 => DOM 생성 함수
const convertToDiscussion = obj => {
const li = document.createElement('li'); // li 요소 생성
li.className = 'discussion__container'; // 클래스 이름 지정
//avatarWrapper, discussionContent, discussionAnswered DOM 생성
// discussion 컴포넌트 append
li.append(avatarWrapper, discussionContent, discussionAnswered);
return li;
};
- 데이터를 화면에 렌더링 하는 함수
// 데이터 렌더링 함수
const renderContent = (element, page) => {
// 글 목록 초기화
while (element.hasChildNodes()) {
element.removeChild(element.lastChild);
}
// 현재 페이지부터 표시될 최대 컨텐츠까지 반복하여 리스트 생성 함수 실행 후 컨텐츠 표시
// ... 직전 페이지로부터 넘어온 현재 i값을 한 페이지의 최대 컨텐츠 그리고 전체 컨텐츠 이내의 범위에서 증감시키며,
// ... 배열의 i번째 요소로 DOM 생성함수를 호출하여 element(ul)에 추가.
for (let i = (page - 1) * maxContent; i < page * maxContent && i <= numOfContent; i++) {
// 로컬 스토리지에 저장된 data[i]가 존재하는 경우,
// data[i]에 대하여 DOM 생성함수를 실행한 뒤 화면에 렌더링한다.
if (data[i]) {
element.append(convertToDiscussion(data[i]));
}
}
return;
};
- 버튼 DOM 생성 함수
const makeButton = id => {
const btn = document.createElement('button');
btn.className = 'btn__page--btn';
btn.dataset.num = id;
btn.textContent = id;
btn.addEventListener('click', e => {
// 특정 버튼을 클릭하면 활성화, 다른 버튼은 비활성화 ***
// btns.children이 유사 배열이기 때문에 forEach를 사용하기 위해 다른 방법을 썼다.
Array.prototype.forEach.call(btns.children, btn => {
if (btn.dataset.num) btn.classList.remove('active');
});
e.target.classList.add('active');
// 페이지 번호를 넣어 렌더 함수 호출
renderContent(ul, parseInt(e.target.dataset.num));
});
return btn;
};
- 버튼 렌더링 함수
const renderButton = page => {
// 버튼 목록 초기화
while (btns.hasChildNodes()) {
btns.removeChild(btns.lastChild);
}
// 현재 페이지부터 최대 페이지까지 번호를 매겨 버튼을 생성
for (let i = page; i < page + maxButton && i <= maxPage; i++) {
btns.append(makeButton(i));
}
// 첫 버튼 활성화
btns.children[0].classList.add('active');
// 페이지 이동 버튼 앞 뒤로 추가
btns.prepend(prev);
btns.append(next);
// 페이지 이동 버튼 필요 여부 확인
// 현재 페이지가 최대 버튼 갯수보다 같거나 작으면 prev가 없어도 됨.
if (page <= maxButton) btns.removeChild(prev);
// 현재 페이지가 max 페이지 갯수보다는 작으면서
if (maxPage - page < page && page <= maxPage) btns.removeChild(next);
};
- 버튼의 페이지이동 이벤트 핸들러와, 데이터 + 버튼 렌더링을 동시에 핸들링하는 함수
// 페이지 이동 함수
const goPrevPage = () => {
page -= maxButton;
render(page);
};
const goNextPage = () => {
page += maxButton;
render(page);
};
// prev 버튼 생성
const prev = document.createElement('button');
prev.classList.add('btn', 'prev');
prev.textContent = '< 이전';
prev.addEventListener('click', goPrevPage);
const next = document.createElement('button');
next.classList.add('btn', 'next');
next.textContent = '다음 >';
next.addEventListener('click', goNextPage);
// 렌더링 핸들러 함수
function render(page) {
renderContent(ul, page);
renderButton(page);
}
전체 코드를 내가 직접 짠 것은 아니고 친절하게 잘 설명해주신 블로그가 있어서 참조를 한 뒤 내 코드에 맞게 변형했다. 출처는 하단 참고자료에 남기겠음..! 사실 따라하면서 하다보니 지금 생각하면 크게 어렵지 않았던 것 같다. (기억이 미화되었나)... 코드가 약간 복잡한 것은 있는데, 각 함수간 동작 방식을 잘 정리하면서 진행하면 크게 어렵지는 않은 것 같다.
SUMMARY
잘 한 것
- 매우 쉬고 싶지만 오늘 헤맸던 내용을 정리했다!
- 완성을 위해서 끝까지 노력한 것.
보완할 점
- 생각보다 시간이 오래걸려서 다음 공부에 차질이 있을 수도 있을 것 같다.
- 계획이 꼬이면 조급하고 불안한 마음이 드는데, 죽지 않으니 잘 다스려 볼 것. ㅋㅋ
- 오늘도 밥을 대충 먹었다. 아침에 아몬드 한 줌 먹은 것은 좋았음.
느낀 점
- 페이지네이션을 순수 자바스크립트로 구현하려니 힘든 것 같다. 아마 리액트로 구현하면 조금 더 쉽지 않을까 싶다. 그래도 바닐라 자바스크립트가 베이스가 되는 만큼 확실하게 익혀두고 싶다...! 시간이 될 때 투두 리스트 같은 것을 만들며 연습해보면 좋지 않을까 싶다.
- 이제 곧 스터디 발표에, 8월 첫째 주 부터 리액트 스터디도 시작하는데 과연 일정을 잘 감당할 수 있을까? 역시 주말을 잘 활용해야겠지.
참고자료
https://nohack.tistory.com/125
간단한 페이지네이션 구현하기
Pagination 페이지네이션은 다수의 콘텐츠를 여러 페이지로 나누고, 이전 또는 다음 페이지로 넘어가거나 특정 페이지로 이동할 수 있는 버튼을 제공하는 기술입니다. 페이지네이션은 공통된 주제
nohack.tistory.com
https://ossam5.tistory.com/251
[JS강좌] 30강 dataset : 문서객체 사용자정의속성 - 오쌤의 니가스터디
1. HTML data-* 속성 - HTML태그들의 속성명은 전부 지정되어 있습니다. - 하지만 사용하다보면 개발자들이 속성을 만들고 싶을때가 있습니다. - 그때 사용할 수 있는 것이 사용자정의 속성입니다. -
ossam5.tistory.com
'TIL' 카테고리의 다른 글
| [Day 21] 2022-0721 : 고차함수! (0) | 2022.07.21 |
|---|---|
| [Day 20] 2022-0720 : 섹션 1 마무리✨ (0) | 2022.07.20 |
| [Day 18] 2022-0718 : solo 프로젝트 -1 (0) | 2022.07.18 |
| [Day 17] 2022-0715 - 회원가입 페이지 유효성 검사 (0) | 2022.07.15 |
| [Day 16] 2022-0714 (0) | 2022.07.14 |