목, 금은 Git을 배우고 솔로프로젝트로 나만의 아고라 스테이츠를 만들어 배포해보는 시간을 가져본다!
Unit8에서 했듯이 Git은 분산형 버전 관리 시스템임, 깃헙의 리모트 리포지토리와 컴터의 로컬 리포지토리가 있음!
과정
git init
: 해당 디렉토리에 로컬 Git repository를 생성, 개발git add
: 코드를 작성하고 저장하는 공간, 작업 공간(work space)의 파일 및 디렉토리를 git의 관리 하에 있는 상태로 올려줄 수 있음, 이 영역이 staging areagit status
: 커밋하기 전 staging area의 상태를 확인
- 커밋 조건 1. 같은 용도 물건(코드파일)을 하나의 무빙박스(SA)에 넣기
- 커밋 조건 2. 무빙 박스의 내용물에 대한 간단한 라벨링
git commit -m "commit message"
: 라벨링, 커밋 메세지 - 코드의 용도 저장 ex)git commit -m "나만의 아고라스테이츠 html, css 완성"
git commit
: staging area의 파일은 commit이 가능, commit으로 local Git repository에 내 코드를 기록, staging area의 코드 묶음을 저장
staging area : 커밋하기 전 내용을 기록하는 장소, 코드가 작성된 파일들을 모아둬 그 코드를 하나로 모아두는 과정을 거쳐 그 공간을 뜻함, 온전히 저장하고 싶은 코드를 모아놓은 묶음
git add 경로-파일명
: 그 파일을 staging area로 추가, .
은 현재 경로를 뜻하므로 그 경로의 모든 파일을 추가하는 것임
# Good: 기능(feat) 구현을 확인 가능, 정확한 기술 용어 사용, 짧고 간결함
git commit -m "feat: 인스타 게시글 조회 페이지네이션"
# Bad: 커밋 타입 구분 X, 만연체, 사실 여부를 판단하기 어려운 "효율성"에 대한 코멘트
git commit -m "더 효율적인 인스타 게시글 조회 기능 구현함"
# Very Bad: 어떻게 나은 형식인지 판단하기 어려움, 어떤 기능인지 확인이 어려움
git commit -m "좀 더 나은 형식"
git status
git add code.svg eat.svg repeat.svg sleep.svg
git commit -m "feat: 각 버튼에 맞는 사진 첨부"
git add README.md
git commit -m "docs: README.md 작성"
원격 깃 저장소를 모아놓은 곳은 깃헙!
- Github에서 원격 리포지토리를 생성
- 깃헙 리포지토리 가서 'New' 버튼을 눌러 실행, 오픈 소스인지 아닌지에 프라이빗, 퍼블릭 설정
git remote add name URL
: 로컬 리포지토리에 원격 리포지토리 git url을 등록, name은 원격 저장소 이름(처음은origin
을 씀), URL은 리포지토리 주소,git remote -v
로 확인git push -u remote_name branch
: 로컬 Git repository에 기록한 내역을 원격 Git repository에 push
git push -u origin main
: origin이라는 원격 저장소에 로컬 리포지토리의 main파일 업데이트 함! 근데 같은 브랜치의 이름이라면 덮어쓰기 브랜치는 리포지토리의 임시 폴더? 분기? 느낌, 나중에 합쳐서 수정도 가능해 main은 나두다가 브랜치로 막 바꿀 수 있음
git clone 리포지토리주소
, fork, pullrequest 등을 설명불러오기: git clone 주소
, git pull name branch
커밋: git add 로컬경로
, git commit -m ""
, git push name branch
브랜치: git branch (-v)
, git branch name branch_name
(하위브랜치생성), git checkout (-b) name
(-b: 그 위치에 생성 및 이동), git merge name
,
확인: git log
, git status
, git remote -v(erbose)
등등
취소 및 백업: git reset HEAD(^, ~n) 등
, git stash
깃헙에서 fork 해오고 로컬로 clone해서 로컬 환경 구축하자!!
이거 따라 만들어보는 것이다! 하면서 문제가 발생하면 기록하고, 어떻게 해결했는지의 과정을 중심으로 써보자
그리고 자주 자주 커밋하기!
Discussion의 컴포넌트를 만들어 각각 li에 넣어줄 것임, data.js에 데이터들이 있음
보면 질문을 담을 Section 안에 Discussions 자체와 질문칸을 담을 섹션, 질문 안으로 나뉘는 구조임
그 질문칸은 ul - li 구조를 가진 리스트임
이걸 토대로 하나의 Discussion 컴포넌트의 html 목업을 해보자
<li class="discussion__container">
<div class="discussion__avatar--wrapper">
<img class="discussion__avatar--image"
src="https://avatars.githubusercontent.com/u/12145019?s=64&u=5c97f25ee02d87898457e23c0e61b884241838e3&v=4"
alt="avatar of kimploo">
</div>
<div class="discussion__content">
<h2 class="discussion__title"><a href="https://github.com/codestates-seb/agora-states-fe/discussions/6">[notice] 좋은 질문하는 법</a></h2>
<div class="discussion__information">kimploo / 2022-04-22T14:08:33Z</div>
</div>
<div class="discussion__answered"><p>☑</p></div>
</li>
<li>
요소의 기본 스타일인 점을 보이지 않게 합니다.flex-grow를 이용해 옮겼음
이제 컴포넌트의 구조를 만들었으니 넣을 데이터를 불러와야 할 차례
data.js에 데이터가 41개의 배열로 있음, HTML로 데이터를 보면서 코드를 작성해도되지만 41개를?!
그러므로 DOM을 이용해 추가해보자! JS 코드를 넣으면 DOM의 트리 구조로 변환해주는 사이트도 있음! 보면서 하면 더 쉽게 할 수 있음
우선 DOM + JS 조합으로 요소를 만들고 클래스 이름을 통일화하는 작업을 시작하자
// li 요소 생성 및 클래스 맞춰줌
const li = document.createElement("li");
li.className = "discussion__container";
// div 요소 생성 및 클래스 맞춰줌, 큰 가짓수의 div 먼저 생성
const avatarWrapper = document.createElement("div");
avatarWrapper.className = "discussion__avatar--wrapper";
const discussionContent = document.createElement("div");
discussionContent.className = "discussion__content";
const discussionAnswered = document.createElement("div");
discussionAnswered.className = "discussion__answered";
// ul
const ul = document.querySelector("ul.discussions__container");
// img 요소 제작, data.js의 배열 데이터 가져오기
const avatarImg = document.createElement("img");
avatarImg.src = agoraStatesDiscussions[0].avatarUrl;
avatarImg.alt = "avatar of " + agoraStatesDiscussions[0].author;
// HTML에 맞게 자식으로 넣어주기
avatarWrapper.append(avatarImg);
li.append(avatarWrapper, discussionContent, discussionAnswered);
ul.append(li);
이런 식으로 하면 됨. 물론 리액트가 좀 들어간 render()와 반복문을 써줘서 해야하지만 구조는 어쨌든 이럼, 이제 n을 지정해 41개의 데이터를 렌더링해보자
1부터 끝까지 다 설정해줘야함
// convertToDiscussion은 데이터를 DOM을 통해 HTML로 변환
const convertToDiscussion = (obj) => {
// li 요소 생성 및 클래스 맞춰줌
const li = document.createElement("li");
li.className = "discussion__container";
// 이미지 div 요소 생성 및 클래스 생성
const avatarWrapper = document.createElement("div");
avatarWrapper.className = "discussion__avatar--wrapper";
// img 요소 제작, data.js의 배열 데이터 가져오기
const avatarImg = document.createElement("img");
avatarImg.className = "discussion__avatar--image";
avatarImg.src = obj.avatarUrl;
avatarImg.alt = "avatar of " + obj.author;
// HTML에 맞게 자식으로 넣어주기
avatarWrapper.append(avatarImg);
// content 불러오기
const discussionContent = document.createElement("div");
discussionContent.className = "discussion__content";
// 제목 불러오기
const discussionTitle = document.createElement("h2");
const titleAnchor = document.createElement("a");
titleAnchor.href = obj.url;
titleAnchor.textContent = obj.title;
discussionTitle.append(titleAnchor);
// 인포메이션 불러오기
const discussionInfomation = document.createElement("div");
discussionInfomation.className = "discussion__information";
discussionInfomation.textContent = `${obj.author} / ${obj.createdAt}`;
// 마무으리
discussionContent.append(discussionTitle, discussionInfomation);
// 답변 유무 불러오기
const discussionAnswered = document.createElement("div");
discussionAnswered.className = "discussion__answered";
const isAnswer = document.createElement("p");
isAnswer.textContent = obj.answer === null ? "☑" : "☒";
discussionAnswered.append(isAnswer);
discussionContent.append(discussionAnswered);
// TODO: 객체 하나에 담긴 정보를 DOM에 적절히 넣어주세요.
li.append(avatarWrapper, discussionContent, discussionAnswered);
return li;
};
위에선 만든 엘리먼트들과 객체 데이터의 변수를 연결했다. 이제 그 결과를 ul
에 넣어주는 함수를 구해보자
convertToDiscussion
함수 적용한 뒤 ul
에 추가const render = (element) => {
// 고차함수
// agoraStatesDiscussions.map((pre) => element.append(convertToDiscussion(pre)));
for (let i = 0; i < agoraStatesDiscussions.length; i += 1) {
element.append(convertToDiscussion(agoraStatesDiscussions[i]));
}
return;
};
// ul 요소에 agoraStatesDiscussions 배열의 모든 데이터를 화면에 렌더링
const ul = document.querySelector("ul.discussions__container");
render(ul);
디스커션 추가기능 : 폼 제작, 작성자-본문 작성 후 제출하면 배열 데이터에 쌓임 + 뷰포트에 디스커션 실제로 추가
// 제출
const form = document.querySelector("form");
form.addEventListener("submit", () => {
// submit 이벤트 필수, 새로고침 안되게
// 로컬스토리지화 되면서 새로고침돼도 안없어지니 필요없어짐
// event.preventDefault();
// 제출된 내용(Value) 변수화
const author = form.querySelector("div.form__input--name > input").value;
const title = form.querySelector("div.form__input--title > input").value;
const textbox = form.querySelector("div.form__textbox > textarea").value;
// 들어갈 임시 객체 그릇 만들기
// 입력되면 객체 그릇에 내용 담기
// data.js에 옮기고 convertToDiscussion로 DOM 변환
// render에 넣어서 렌더링 되게 하기
const newObj = {
id: "new id",
createdAt: new Date(),
title: title,
url: "https://github.com/codestates-seb/agora-states-fe/discussions",
author: author,
answer: null,
bodyHTML: textbox,
// 랜덤 이미지 출력
avatarUrl: "https://i.pravatar.cc/300",
};
// 바로 나타나기
ul.pretent(convertToDiscussion(newObj))
// submit 후 빈칸으로 리셋
form.querySelector("div.form__input--name > input").value = "";
form.querySelector("div.form__input--title > input").value = "";
form.querySelector("div.form__textbox > textarea").value = "";
});
new Date(시간).toLocaleString()
메소드 사용하면 됨, 현업에서도 많이 쓰임!
// 데이터를 넣어주면 알아서 해줌, 그냥 쓰면 현재시간 나옴!
new Date(obj.createdAt).toLocaleString()
시간을 표출해주기도 했음!
// 시계
const clock = document.getElementById("clock");
function getClock() {
// 현재 시간 가져옴, 시간분초 다 따로 가져와야함
const date = new Date();
// get~으로 시분초 가져와서 변수 할당
// number이기 때문에 String 변환해 textContent로 갖고오기
const hours = String(date.getHours());
const minutes = String(date.getMinutes());
const seconds = String(date.getSeconds());
// 10 이상 즉 2자리수 이상일 시 0을 붙이게 삼항연사자 썼음
clock.textContent = `${hours < 10 ? `0${hours}` : hours} :
${minutes < 10 ? `0${minutes}` : minutes} : ${seconds < 10 ? `0${seconds}` : seconds}`;
}
getClock();
// 코드 조각이나 함수를 1000ms로 계속 실행시키게 만드는
setInterval(getClock, 1000);
localStorage
의 인터페이스를 활용localStorage.setItem("key", "String")
: 폼 엘리먼트같은 곳에서 제출같은 게 되면 브라우저의 로컬저장소(크롬 개발자도구-애플리케이션-로컬스토리지)에 저장되게 만드는 메소드. ⭐️객체를 넣으려면 JSON.stringify(obj)
필수로 넣어야함, 안그러면 '[object Object]'로 나옴!localStorage.getItem("key")
: 저장된 키의 값을 불러오기, 불러와서 뷰포트에 나오게 하거나 변수 지정 가능!sessionStorage
도 있음! 차이점은 로컬은 영구적(브라우저, 창이 닫아져도 값 유지)이지만 세션은 휘발성을 지님(닫으면 없어짐)newObj
를 setItem
으로 저장 후 getItem
으로 불러와 더미데이터에 추가 하는 방식으로 렌더링// 전역변수에서 설정해 더미데이터 배열에 들어갈 수 있게
let getLocalDates = JSON.parse(localStorage.getItem("agoraLocalData"));
agoraStatesDiscussions.unshift(getLocalDates);
// 제출 이벤트 : pretend는 쓸모 없어졌으니 삭제
form.addEventListener("submit", () => {
// ...중략
localStorage.setItem("agoraLocalData", JSON.stringify(newObj));
}
getItem
쓸 때 JSON.parse()
를 써야한다. 그 이유는 객체 그 자체가 아닌 JSON 문자열 데이터로 나오기에 JSON.parse()
를 써줘 객체로 들어가게끔 해야함여러개의 데이터들을 변환해줄 수 있는 기능을 만들어보자..
이런 식의 구조로 가면 된다
무조건 구현한다.
페이지네이션, 상위로 올라가기 버튼,
레퍼런스