230829.log

Universe·2023년 8월 29일
0

log

목록 보기
3/14
🗓️ 날짜 : 2023.08.29

📚 할 일 :
	- 10to7, 1day 1commit 1post, 1mon 3project
	- Poco jang 클린코드 자바스크립트

📝 오늘의 목표 : 
	- 클린코드 자바스크립트 강의
		- 20[값식문] ~ 26[Early Retrun] 듣고 간단하게 정리하기
        
	- 유튜브 클론코딩 프로젝트
		- Home, Search 컴포넌트 로직 마무리
        
📝 달성한 목표 : 
	- 클린코드 자바스크립트 강의
    	- 20~23
	- 유튜브 클론코딩 프로젝트
    	- Home 컴포넌트
        	- api, 카테고리 필터 fetch 로직 구현
            - 무한 스크롤 1차 구현 (최적화 필요)
            - 버그 fix

⌛ 공부시간 : 11:40 ~ 20:40

✅ 목표달성 : false 😞

Til

클린코드 자바스크립트(Poco Jang)

💡 값식문

Q : 개발자가 문법을 신경써서 지켜야 하는 이유 ?
A : 컴퓨터를 이해시켜야 하기 때문에

React 개발 중 가장 실수하기 쉬운 부분
(JSX 를 사용하는 과정에서)

case 1:

ReactDOM.render(<div id="msg">Hello World!</div>, mountNode);
// transformed to JS
ReactDOM.render(React.createElement('div', {id:'msg'}, 'Hello World!'), mountNode);

case 2:

<div id={if (condition) {'msg'}}Hello Wolrd</div> // X
// transformed to JS
React.createElement('div', {id: if(condition){'msg'}}, 'Hello World'); // X

ReactDOM.render(<div id={condition ? 'msg' : null}>Hello World!</div>, mountNode) // O

case 3: IIFE
즉시 실행 함수를 사용해 ‘문’ 을 ‘값’으로 귀결시킬 수 있다.

const Arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

{(() => {
	for (let i = 0; i < Arr.length; i++) {
		<div>{i}</div>;
	}
})()}
// === 
{ Arr.map((item) => {
		<div>{item}</div>;
})}

값(Value) : ‘42’, ‘Hello’ …
React : props, state 등은 자바스크립트의 ‘값’ 으로 취급된다.

식(Expression) : 하나 이상의 값을 조합하여 새로운 값을 반환 ‘2 + 2’
React : JSX 내부 중괄호 ‘{}’ 를 사용해 ‘식’ 을 삽입할 수 있다. 식은 값을 반환하므로 사용가능.

문(Statement) : 프로그램의 단위, 어떤 작업을 수행하는 것(조건, 반복) 💡 ’문’ 은 ‘값’ 을 반환하지 않는다.
React : 렌더링 로직에 ‘문’을 사용할 수는 있지만 ‘값’을 반환하지 않으므로 JSX 내부에 직접 삽입할 수 없다.

  • JSX 내부에 ‘문’ 을 직접 삽입할 수 없는 몇가지 이유
  1. JSX 자체도 ‘표현식’ 이기 떄문에
  2. 기본적으로 함수적 접근을 지향하고 ‘문’ 은 사이드 이펙트의 발생을 야기하기 때문에
  3. 렌더링과 로직을 분리하는 것이 가독성, 최적화 측면에서 좋기 때문에

💡 삼항연산자

조건 ? () : 거짓()
  • 일관성을 지켜 삼항연산자를 사용하자
  • 조건 분기가 많다면 switch case 문을 고려해보자
  • 삼항연산자의 참, 거짓의 식이 void 를 반환하는 함수라면 사용을 지양하자
  • 삼항연산자를 사용해서 무언가의 값을 만들고 변수로 담아낼 때 사용하는 것을 지향하자

💡 단축평가

&&
	- 첫 번째 피연산자가 falsy 일 경우, 두 번째 피연산자를 평가하지 않음.
	- 두 번째 피연산자가 truthy 일 경우, 두 번째 피연산자를 반환.

const fetchData = data && something();
// data의 값이 falsy(undefined, null) 일 경우 somthing 함수가 호출되지 않음.

||
	- 첫 번째 피연산자가 truthy 일 경우, 두 번째 피연산자를 평가하지 않음.
	- 첫 번째 피연산자가 falsy 일 경우, 두 번째 피연산자를 반환. 

const fetchData = data && something();
// data의 값이 truthy(undefined, null) 일 경우 somthing 함수가 호출되지 않음.
  • 문자열은 truthy 한 값이므로 React 등에서 조건부 렌더링에 활용하기 좋다.

Project Issue

fetch 로직을 전부 다시 수정했다.
유튜브 api 를 그대로 사용하는 것이 아니라 필요한 정보만 간추려서 fetch 할 수 있도록 하기 위함.
이렇게 api 를 가공하는 쪽이 로직은 조금 더 무거울테지만
렌더링 하는 부분에서는 조금 더 가볍고 직관적일 것 같다.

현재 로직의 타입이 전부 any 로 들어가 있는데,
api 를 계속 수정하고 받아오는 데이터가 달라지다 보니까 수정하고 또 수정하는 것이
번거로워서 임시방편으로 any 스크립트를.. 😒
자꾸 수정되니까 개발 생산성 측면에서 매우 좋지 않다.
저번주인가? 외주 관련 화상면접을 진행했을 때,
타입스크립트의 생산성 저하에 대해서 생각해보신 적 없냐고 여쭤보셔서
오히려 자동완성이나 협업 간 소통에 이점이 있다고 생각해서 생산성이 좋을 것 같다고
말씀드렸는데, 제대로 된 복선이었나 싶기도 하고.

로직을 전면적으로 수정했더니 youtube api 를 부르는 횟수? 토큰? 이
획기적으로 줄어들었다. 이유를 잘 모르겠어서 리펙토링 때 분석해볼예정.

youtube 의 videos api 에는 게시자의 프로필 정보가 담겨있지 않다.
그래서 어떻게 하면 실제 유튜브 카드 컴포넌트에 필요한 모든 정보를 가져올 수 있을까 고민하다가
로직을 분리해서 한번에 요청하면 좋을 것 같았다.
생각한 로직의 흐름은 다음과 같다.

우선 필요한 정보를 videos api로 요청하는 로직을 구상했다.
필요한 정보는 snippet, contentDetails, statistics.
part 라는 쿼리 파람에 string 으로 넣으면 각각의 정보를 반환해준다.
추가적으로 무한스크롤, 카테고리 별 검색을 위해 쿼리파람의 pageToken, categoryId 값을
유동적으로 받을 수 있도록 한다.

  const params = {
    part: "snippet, contentDetails, statistics",
    chart: "mostPopular",
    regionCode: "KR",
    maxResults: 10,
    pageToken,
    ...(categoryId && { videoCategoryId: categoryId }),
  };

이런식으로.
...(categoryId && { videoCategoryId: categoryId }),
이 부분이 조금 재밌는데, 단축평가를 활용한 객체 풀어넣기.
categoryId 가 truthy (값이 있으면) 라면 우항의 객체를 생성하고
전개연산자로 풀어 params 객체에 병합하는 방식이다.

고맙게도 channels 라는 api 가 있어 videos 의 채널 id 를 기준으로
해당 채널 정보를 가져올 수 있다. 프로필사진, 채널명 같은거.
당연히 map 을 돌려서 개별 요청을 하는건 말도 안된다고 생각했었는데,
채널 id들을 한번에 쿼리파람으로 넣어서 요청하면
한번의 요청으로 모든 채널정보를 가져올 수 있다.

export const fetchChannelInfo = async (channelIds: string[]) => {
  const params = {
    part: "snippet",
    id: channelIds.join(","),
  };

  const response = await instance.get("/channels", { params });
  return response.data.items;
};

당연히 배열을 쿼리파람으로 넣을수는 없으므로
이런식으로 채널id 의 배열을 파라미터로 받아서 join 메소드로
'쉼표로 구분한 문자열로 치환' 하여 집어넣는다.

그러면 이제 둘을 합쳐서 원하는 정보들만 모아놓으면 된다.

export const getPopularVideos = async ({
  pageToken,
  categoryId,
}: {
  pageToken?: string;
  categoryId?: string;
}) => {
  const { videos, nextPageToken } = await fetchPopularVideos({
    pageToken,
    categoryId,
  });
  const channelIds = videos.map((video: any) => video.snippet.channelId);
  const channels = await fetchChannelInfo(channelIds);

  const items = videos.map((video) => {
    const channelInfo = channels.find(
      (channel) => channel.id === video.snippet.channelId
    );
    return {
      id: video.id,
      title: video.snippet.title,
      duration: video.contentDetails.duration,
      thumbnail: video.snippet.thumbnails.medium.url,
      publishedAt: video.snippet.publishedAt,
      viewCount: video.statistics.viewCount,
      publisher: channelInfo.snippet.title,
      publisherProfileImg: channelInfo.snippet.thumbnails.default.url,
    };
  });

  return { items, nextPageToken: nextPageToken };
};

순차적으로 실행시켜서 find 메소드로 id를 맞춤해주고 원하는 정보만 return 하면 된다!
아직 리펙토링도 안했고 타입도 제대로 지정 안해줘서 보기 싫은데
차후에 수정할 것.

instance 를 class 화 시켜서 context 로 만들어 커스텀 훅으로 묶어버리면
mock 데이터를 활용하기도 편하고 객체지향적으로 관리할 수 있다는 것 같다.
굉장히 신기한 방법이어서 리펙토링 할 때 사용해보려고 한다.
한번 봐서는 제대로 로직이 이해가 잘 가지 않아서 몇 번 돌려봐야 할 듯.


Feedback

어떻게 첫 날 부터 지각을 할 수 있지?
진짜 회사였으면 많이 혼났을지도 모르겠다.
아침 운동을 끝내고 시간이 조금 남아서 이마트에 다녀온다는게
이마트가 10시에 여는줄은 몰랐지 😖
이런 예상치 못한 변수에도 대비할 것.

강의를 가볍게 6강 보겠다고 계획했지만
보고나서 여러가지 궁금한 점을 찾아보고 직접 두드려보는 데 시간을 너무 오래 썼다.
강의 시간은 30분도 채 되지 않았는데 2시간을 넘게 구글링 하는 데 써버려서
이러다가는 프로젝트에 손도 못 대고 끝날 것 같아서 내일 보자고 덮어버렸다.
이런건 어떻게 대책을 세우면 좋지 ?
궁금함을 조금 참아야 할까 ?
조금 고민해 볼 것.


예상되는 내일의 목표

  • Home 컴포넌트 마무리, Search 컴포넌트 개발
  • api의 골격은 완성했으니까 이제는 정말 금방할 수 있을 것 같다.
  • 클린코드 자바스크립트 강의 이어서 보기.
profile
Always, we are friend 🧡

0개의 댓글