[항해99] Week 4 [7.11 - 7.16]

Hajun Song·2022년 7월 17일
0

Weekly I Learned

목록 보기
4/7
post-thumbnail

[항해99] Week 4 [7.11 - 7.16]

0. ✅심화와 입문 사이

입문주차를 마치고 진행되었던 숙련주차.
주어진 강의는 심화반 강의, 주어진 과제는 입문주차와 별 차이가 없는 과제.
뭐랄까. 어렵지만 아쉬웠다. 쉬웠지만 값졌다.

🐱‍💻Note
입문보다 먼 심화보다는 가까운.
기초가 모자랐던 이들에겐 기초를 다져갈 시간적 여유를.
깨달은 이들에겐 나누며 정리할 수 있는 기회를. 여름이었다.

0-0. ✅숙련주차 개인과제

게시판을 만들어라.
그렇게 숙련주차 개인과제가 시작되었다.
항해가 바라는 모습은 reduxfirebase를 이용한 데이터 유지 및 관리 능력.
내용은 아무런 상관이 없었다.

핑크색으로 가득한 게시판도 나왔고 디자인이 이쁜 검은 게시판도 나왔다.
어차피 만들라는 것 만들텐데 추가적인 기능 구현 연습에 집중했으면 어땠을까...
숙련주차 개인과제 보러가기

탑건을 보고 오랜만에 통제가 하고싶었다.
공식문서를 참고하는 지금이 MPM을 암기하던 그때보단 나으리라.

🐱‍💻Note
모든 경험은 영감의 아버지
영감... 잡혀가지 않게 조심해요.. ROKAF가 공개한 F-16 BEM

트러블 슈팅 #0

숙련주차 개인과제로 간단한 단어장을 만들었다.
기본적으로 각각의 단어가 차지하는 단어 카드의 사이즈가 문제였다.

#0-0. 단어마다 정의의 길이가 달랐고 그에 따라 카드의 크기가 제각각이 되었다.

function Contents({ idx, dict }) {
	...
  var def = React.useRef(dict.def);
	...
return (
    <Col xs={12} md={6} lg={4}>
          ...
          <h5 ref={def}>
            {dict.def}
          </h5>
          ...
    </Col>
  );
}


단어 추가시 입력할 수 있는 정의의 길이를 제한 할 수 있었다.
하지만 그러면 더이상 단어장의 의미가 없었다.


#0-1. 단어카드에 나타나는 글자수를 제한하자.

그래서 단어카드에 나타나는 글자수를 제한하기로 했다.
substring()삼항연산자를 이용해서 일정한 길이로 정의를 잘랐다.
화면의 넓이에 비례해서 글자수를 책정하는 것도 나쁘지 않겠다.

	...
    <h5 ref={def}>
      {dict.def.length > 30
        ? dict.def.substring(0, 30) + "..."
      	: dict.def}
    </h5>
	...


빨간 투명판이 부록된 토익 영단어 암기카드도 숨넘어갈만큼 깔끔한 단어카드가 되었다.
하지만 숨겨진 단어의 정의를 볼 수 있는 방법이 필요했다.


#0-2. 마우스를 올리면 모든 단어를 볼 수 있게 해주자.

eventlistener를 이용해 mouseover에 작동하는 기능을 만들어봐야겠다 생각했다.
단어 카드에 마우스를 올렸을 때 필요한 변화는 총 두가지였다.
0. 다른 카드들이 이 이벤트에 의해 위치가 변하지 않을 것.
1. 단어 카드에 단어의 정의가 모두 표현될 것.

	...
const hoverShow = () => {
    box.current.style.position = "absolute"; //0.
    box.current.style.minWidth = "420px";
    box.current.style.width = "20%";
    word.current.innerText = dict.word;
    def.current.innerText = dict.def; //1.
    ex.current.innerText = dict.ex;
  };
React.useEffect(() => {
  box.current.addEventListener("mouseover", hoverShow);
  box.current.addEventListener("mouseout", hoverOut);
	...


기능이 구현되고 끄덕. 어?. 어랏.
데스크탑과 태블릿 환경에서는 문제가 없었다.
문제는 모바일이었다.

단어장은 모바일 환경을 고려해서 반응형으로 제작되었다.
데스크탑에선 한 줄에 3개의 단어, 태블릿에선 2개, 모바일에선 1개.
이벤트에 의해 positionabsolute가 되는 과정에서 문제가 발생했다.

absolute DOM은 자신의 공간을 차지하지 않기 때문이었다.
그렇다, 데스크탑과 태블릿에선 나머지 카드가 줄을 지켜주니 구조변화가 없었다.
하지만 모바일에선 absolute가 되는 순간 아래의 카드가 위로 올라왔다.


#0-3. 모바일에서 이상해! media query? if!

기능을 ref를 이용해 DOMcss 값들을 바꾸는 방식으로 구현했다.
기존 css에서는 @media query를 이용해 디바이스 조건을 걸어줄 수 있었다.
이 부분을 가지고 멍청이처럼 하루 종일 고민했다.
eventListener에서 @media 사용하는 법.
js에서 @media 사용하는 법.

그냥 if문 쓰면 되는걸...

const hoverShow = () => {
    if (window.innerWidth > 767) {
      //현재 브라우저의 넓이가 모바일보다 클 때
      box.current.style.position = "absolute";
      box.current.style.minWidth = "420px";
      box.current.style.width = "20%";
    }
    word.current.innerText = dict.word;
    def.current.innerText = dict.def;
    ex.current.innerText = dict.ex;
};

브라우저가 모바일보다 클때만 absolute로 바꾸고 그 외엔 static을 유지하도록 처리했다.
left: 기존 단어카드 순서
middle: mouseover시 absolute가 적용되어 BINGO와 CHECK가 위로 올라감
right: if문을 이용해 모바일 환경에선 mouseover시 static 유지.

해결완료.

0-1. ✅숙련주차 회고

개인 블로그에 항해 시리즈는 다 적으려고 했다.
하지만 주특기 입문주차를 끝내며 WIL 적기도 벅차다는 것을 직감했다.
결국 작문이 오래 걸리는 관계로 포기하게 되었다.

배우는 것들을 그때그때 조금씩 끄적이는 정도면 괜찮겠지..
많이 배운 시간이었다.

🐱‍💻Note
지속 가능한 삶, 지속 가능한 배움, 지속 가능한 발전
한 주에 120시간이 중요한가. 한 주에 100시간이 중요한가. 한 생의 100년이 중요하다.


1. 🔍What I Learned

🐱‍💻Note
사람은 죽지만 정보는 끝까지 떠돈다
0. 서버 기다려주기 async / await
1. EventListener에서 media query 따라하기
2. submit! 가고싶은 대로 간다!
3. git add 따라가기


2. 🔍함수형 컴포넌트

지난 WIL에서 클래스형 컴포넌트의 LifeCycle을 정리했다.

지난 WIL 보러가기

하지만 숙련주차 기간동안 함수형 컴포넌트만 주구장창 사용했다.
함수형 컴포넌트의 LifeCycle도 다룰 필요가 있었다.

🐱‍💻Note
지속 가능한 삶, 지속 가능한 배움, 지속 가능한 발전
한 주에 120시간이 중요한가. 한 주에 100시간이 중요한가. 한 생의 100년이 중요하다.

2-0. 🔍함수형 컴포넌트의 LifeCycle

함수형 컴포넌트에서는 기본적으로 함수가 진행되고 return값을 Mount한다.
클래스형constructor함수형에서 함수 내부 선언에 의해 정의된다.

하지만 클래스형의 나머지 LifeCycle 단계들이 남아있다.
이것들의 구현은 함수형을 사용하기 위해 반드시 선행이 필요한 전제조건이었다.

  • componentDidMount
  • componentDidUpdate
  • componentWillUnmount

state가 바뀌면 컴포넌트는 리렌더링이 일어난다.
이런 짧은 조건조차도 함수형에서는 state를 구현하지 못하면 실현 불가능하기 때문이다.
리랜더링이 일어나지 않는 컴포넌트를 어디에 쓰겠는가.

함수형 컴포넌트에서 사용 할 수 있는 클래스형 컴포넌트의 기능들을 구현한 개념이 있다.
바로 리엑트 훅이다.

2-1. 🔍React Hook

Hook은 클래스형 컴포넌트를 작성하지 않고도 함수형 컴포넌트에서 state와 여러 React의 기능들을 사용할 수 있게 해주는 기능이다.

React HookReact 함수 컴포넌트에서만 호출되어야 한다.

🐱‍💻Note
배우는 속도 > 정리속도
또 이 딜레마가 찾아왔다. useRef, useMemo 등.. 많이 배운다. 정리하자.
React Hook - [개념정리] React Hook 모아보기 (velog)

🔍React.useState()

클래스 컴포넌트에서 사용하던 state를 함수형 컴포넌트에서 사용할 수 있게 해주는 훅이다.

const [stateName, setStateName] = React.useState('default')

함수형 컴포넌트에서 useState를 이용하면 두가지를 반환한다.
첫번째 요소로는 state가 반환된다. 초기값은 매개변수로 제공한 값이다.

const [name, setName] = React.useState('hajun')
//name이라는 state 생성, 초기값은 'hajun'
console.log(name)	// 결과 : 'hajun'

두번째 요소로는 state를 수정할 수 있는 setter함수 setState가 반환된다.

const [name, setName] = React.useState('hajun')
console.log(name)	// 결과 : 'hajun'
setName('Peter')	//함께 반환된 name이라는 state를 수정
console.log(name)	// 결과 : 'Peter'

💭 왜 name의 값을 직접 바꾸지 않나요?

let [name, setName] = React.useState('hajun')
name = 'Peter'
console.log(name)	// 결과 : 'Peter'

name을 직접 바꾸는 행위는 state 변경의 특징인 리랜더링을 발생시키지 않습니다.
state로서 사용이 필요하면 함께 제공되는 setter함수를 사용해야합니다.


💖만들어진 state 뿐만 아니라 setter함수또한 자식 컴포넌트로 전달하여 사용 가능합니다.

let [name, setName] = React.useState('hajun')
return (
  <Feed name={name} setName={setName}/>
)

🔍React.useEffect()

클래스 컴포넌트에서 사용하던 LifeCycle을 함수형 컴포넌트에서 사용할 수 있게 해주는 훅이다.

useEffect(() => {
//0. componentDidMount + componentDidUpdate내용
	return () => {
  	//componentWillUnmount내용
}
})

함수형 컴포넌트에서 useEffect를 이용하면 LifeCycle을 어느정도 구현 가능하다.

0.을 보면 마운팅과 업데이트 모두 포함한다.
렌더링 이후에 발생하는 것으로 생각하면 된다. 이미 DOM이 업데이트 된 후에 실행된다.

function Example() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
    //최초 마운트와 업데이트 이후(count 계산 이후) 작동
    //이 예시는 setter 함수에 의해 리랜더링 되어 작동
  });
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

💖두번째 배열 인수를 사용하여 Effect를 건너뛰게 할 수 있습니다.
다음 랜더링 시 두번째 인수에 변화가 없다면 Effect가 실행되지 않습니다.

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // count가 바뀔 때만 effect를 재실행합니다.
  • 이때 배열 내에 여러 개의 값을 넣을 수도 있습니다.
    그중의 단 하나만 다를지라도 Reacteffect를 재실행합니다.

3. 🔍Firebase

개인과제를 진행하며 db가 필요해서 Firebase에서 제공하는 Firestore을 사용했다.
앞으로 Auth 뿐만아니라 서버리스 서비스를 위해 여러가지 기능 사용이 예정되어 있다.

3-0. Firestore db 가지고 놀기

//firebasePrac.js
//데이터 불러오기와 추가하기는 상위 폴더인 컬렉션 정보가 필요

//컬렉션 정보
collection(db, "mpm_words");
//db에 있는 mpm_words 컬렉션의 컬렉션 정보

//데이터 불러오기 getDocs
React.useEffect(async () => {
  const query = await getDocs(collection(db, "mpm_words"));
  //db에 있는 mpm_words 컬렉션에서 가져온다.
  console.log(query);
  query.forEach((doc) => {
    //문서 갯수만큼 반복
    console.log(doc.id, doc.data());
    //문서 id와 문서 데이터
  });
}, []);

//데이터 추가하기 addDocs
React.useEffect(async () => {
  const docRef = await addDoc(collection(db, "mpm_words"), {
    ////db에 있는 mpm_words 컬렉션에 , 이후의 내용을 추가한다.
    word: "ABORT",
    def: "Directive call to cease action, attack, event, or mission.",
    ex: "ACACIA, COCA 1. ABORT.",
    num: 0,
  });
}, []);

//=================//
//데이터 수정하기와 삭제하기는 대상 문서 정보가 필요

//문서 정보 doc
doc(db, "mpm_words", "word1");
//db에 있는 mpm_words 컬렉션의 word1 문서

//데이터 수정하기 updateDoc
React.useEffect(async () => {
  const docRef = doc(db, "mpm_words", "word1");
  await updateDoc(docRef, {
    word: "BINGO",
    def: "Out of Fuel",
    ex: "ACACIA, COCA 1. BINGO.",
    num: 0,
  });
}, []);

//데이터 삭제하기 addDocs
React.useEffect(async () => {
  const docRef = doc(db, "bucket", "word1");
  await deleteDoc(docRef);
}, []);

🐱‍💻Note
Firebase - 작성중


4. ✅주특기 심화주차에 들어가며

✅ 한주간 약속한 Code Convention을 잘 지켰는가?

  • Prettier - Code formatter Extensions 만세!!
  • 기본적인 가독성 부분은 Prettier를 이용했지만 여전히 명명법은 쉽지 않다.

🐱‍👤TODO
아는 것과 모르는 것을 정리하는 것이 시작
기회가 되면 Extensions 정리랑 라이브러리 정리도 해봐야겠다.

profile
일단 똥을 싸라, 그리고 박수칠 때 까지 닦아라.

0개의 댓글