치춘짱베리굿나이스
[프리온보딩] 220508 강의 메모 01 (그룹과제 코드리뷰) 본문
서론
항상 일은 더 생기기 때문에 이것을 염두하고 미리미리 작업해야 한다
일주일이면 걸릴 과제라면 한달은 잡아놓고 해야 넉넉함
수정사항은 계속 생기기 때문
코드리뷰
1팀
handleChange 이벤트 받아오기
const handleChange = ({currentTarget}) => {}
- e에서 currentTarget 받아올 때 구조분해 할당으로 받아오면 알아보기 힘들다
return값 내보낼 때 객체로 묶어 내보내기
return [date, {handlePrevClick, handleNextClick, handleCalChange}];
return {
date,
handlePrevClick,
handleNextClick,
handleCalChange
};
- 위의 반환문을 아래의 반환문으로 작성할 수 있다
라이브러리
- 특정 요소 바깥을 클릭할 때 이벤트를 발생시키고 싶다면
useRef
와 커스텀 훅 라이브러리 (react-use
) 를 사용하면 쉽다 - 날짜 포맷 변경은
dayjs
를 사용하면 쉽다
기타 내용
- 코드가 200줄이 넘어간다 → 좋지 않음
- 클릭 등의 이벤트가 걸려있지 않을 경우 굳이
button
태그를 사용할 필요가 없다 - CSS로 짧게 구현할 수 있는 내용이라면 굳이 라이브러리로 작성할 필요가 없음
- 투두 리스트를 보여줄 때
filter
를 사용하면 필터링된 데이터를 바로 넣어줄 수 있을 텐데 - 배열
map
메서드 안에서 함수 선언하지 마세요 (바깥에다 선언해서 불러오기)
2팀
key에 인덱스 (i) 넣지 말라는 말 무시하기
{
arr.map((v, i) => {
const key = `test-${i}`;
return (
<div key={key}>{v}</div>
);});
}
- 린터가
key
값에 인덱스 넣지 말라고 경고 띄우면key
를 map 내부 함수 최상단에 선언 및 초기화해주고 그key
를 불러와서 쓰면 된다
린터 잘 지키기
- 노란줄, 빨간줄 나오지 않게 하세요 (다 지워주기)
- 노란 줄 (warning) 도 안 나오도록 해주는 것이 좋다
- 어지간한 에러는 경고문구만 잘 봐도 해결된다
라이브러리
localStorage
는 변수를string
으로 저장하기 때문에storejs
라이브러리를 사용하면JSON.stringify
나JSON.parse
등의 함수를 일일이 사용할 필요 없이 쉽게 로컬 스토리지의 값을 가져오거나 저장할 수 있다
기타 내용
- prettier 씁시다..
- 함수 내에서만 사용하는 변수는 함수 내에 선언하기 (컴포넌트 상단에 선언하면 컴포넌트 렌더링될때마다 계속 재선언된다)
input
요소에 값을 입력하고 엔터로 제출되게 할 때addEventListener
를 사용하는 사람은 나쁜 사람 ⇒form
태그 사용
3팀
라이브러리 쓰기 vs low level 에서 구현하기
- 원리를 알고 공부하는 용도로는 직접 구현하는것도 좋은데 라이브러리를 사용하는게 훨씬 직관적이고 간단하긴 함
- 다만 라이브러리가 작동하는 원리를 알고 있는 게 좋겠다
- 너무 사소한 것까지 (간단한 사칙연산 같은...) 라이브러리를 갖다 쓰는 행위만 지양하면 된다
기타 내용
- 에러 하나도 안뜨는거 너무 좋아요
- json 잘라서 반환하는 함수 예외처리는 배열 반환 말고 객체 반환이 나을것같다
- 자바스크립트에서 기본 제공되는
alert
는 안 쓰는 것이 좋다 ⇒ 경고창이 뜨면 페이지 전체 코드가 멈춰버리기 때문 - 이벤트가 발생하면 이벤트 핸들러 내에
useRef
를 이용하여 특정input
에 포커스를 주는 것 좋은듯
4팀 (우리팀임)
setState만 하는 핸들러는 굳이 핸들러로 뺄 필요가 없다
const handleButtonClick = (v) => {
setValue(v);
}
<button ... onClick={() => handleButtonClick(v)} >
버튼
</button>
<button ... onClick={() => setValue(v)} >
버튼
</button>
- 어차피
onClick
내에 화살표 함수를 작성해야 하는 상황이니 그냥setState
를 가져와서 작성해도 상관없음
컴포넌트를 너무 썰어도 문제다
- 너무 잘게 썰면 오히려 어떤 컴포넌트가 무슨 역할을 하는지 알아보기 어렵게 된다
- 간단한 투두리스트 제작이 너무 복잡해졌다
html 요소 안쪽을 너무 복잡하게 만들지 말고 밖으로 빼자
<div>
{ arr
.filter(foo)
.filter(foo2)
.map(
...
)
}
</div>
const filtered = arr.filter(foo).filter(foo2);
<div>
{ filtered.map(...) }
</div>
- 컴포넌트가 렌더링될 때마다 저
arr.filter.filter
부분이 계속 재작동한다 - 차라리 jsx 구문 안쪽에 중괄호로 감싸서 넣지 말고 로직 부분으로 빼버리자
useMemo, useCallback
const filtered = arr.filter(foo).filter(foo2);
const filtered = useMemo(() => {
return arr.filter(foo).filter(foo2)
}, [arr, foo, foo2]);
- 수식이 복잡해질 경우
useMemo
를 사용하면 리렌더링마다 불필요하게 계산되는 것을 줄이고 의존성을 갖는 특정 상태값이 변화할 때만 재계산되도록 캐싱을 할 수 있다 - 복잡한 수식은 연산속도도 오래 걸리는데, 이를 사용하여 반복적인 연산을 줄이고 속도를 개선할 수 있음
- 렌더링될 때마다 무조건 함수나 변수를 새로 만들기보다는, 의존성을 갖는 값이 변화할 때만 새로 계산하거나 함수를 생성하는 식으로 속도를 개선하지만, 등가교환으로 메모리를 더 잡아먹으므로 너무 남용하는 건 또 좋지 않다 (굉장한 성능 개선이 있는 건 아니므로 너무 습관적으로 감싸지 말자)
useMemo
는 변수를 저장하고,useCallback
은 함수를 저장한다 ⇒ 자세히 알아봅시다
라이브러리
slick.js
⇒ 드래그로 좌우 스크롤 구현할 수 있게 도와주는 라이브러리 (carousel)
기타 내용
- warning 다 없애버리세요
- 와 세상에 키보드를 눌러야 움직인다니!
- (메뉴) 와 비주얼 쥑이네 여기 근데 아무짝에도 쓸모없어 보기좋은떡이 먹기에도 좋습니다
- 초기값같은건 상수화해서 컴포넌트나 로직 바깥으로 빼놔야 가독성이 올라감 (
setState
함수 내에 박아놓지 말고 상수화해서 넣자) - 전역 상태관리 라이브러리를 안 써서 고생하고 계시는군요
- 메뉴 부분 등에 있는 컴포넌트들이 장식이 아니라 실제로 의미있는 동작을 했더라면 더 좋은 투두앱이 되었을 것 같다
5팀
리액트 가족관계
- 부모자식간엔 사이가 좋다 (서로
props
를 주고받을 수 있다) - 형제간엔 사이가 좋지 않다 (부모를 통해야만
props
를 전달받을 수 있다) - 할아버지와 손주간에도 사이가 좋지 않다 (부모를 통해야만
props
를 전달받을 수 있다)
드래그 동작
- 컴포넌트를 누르고 있는 상태에서 (
onMouseDown
) 좌표값을 얻고, 컨테이너의 좌우 너비 등에 비례하여 마우스를 뗄 때까지 (onMouceUp
) 드래그되도록 (onMouseMove
) 제작 document
에addEventListener
를 거는 것보단useRef
를 쓰는게 좋지 않았을까- 컴포넌트가 마운트되었을 때 이벤트리스너를 붙이고, 언마운트될 때 이벤트를 제거하는 게 좋을 것 같다 (마우스를 떼고 붙일 때 이벤트 리스너를 걸고 제거하면 문제발생 여지 높음)
- ⇒ 컴포넌트 바깥으로 마우스가 빠져나가면 이벤트가 동작하지 않아서
setTimeOut과 clearTimeOut
setTimeOut()
을 사용할 땐clearTimeOut
도 같이 써줘야한다 (쌍으로 움직여야 함)- 같이 써주지 않으면 설정한 시간이 흐르고 있는 도중 다른 동작을 수행했을 때 동작이 꼬여버림
- 예시: 라우터를 이용한 페이지 이동으로 현재
setTimeOut
이 걸려있는 컴포넌트가 시간이 흐르던 도중 언마운트 될 때 오류발생
컴포넌트 옆으로 밀었을 때 동작 나오게 구현
overflow-x
속성으로 스크롤을 만든 다음 스크롤을 숨기고, 스크롤 offset을 주면 구현이 조금 더 쉬웠을지도
기타 내용
useRef
랑current.style
을 써서 스타일을 다르게 먹일 필요가 없다 클래스를 지정하면 되었을텐데..props
를 건네줄 때 {... {INT_TODO
,CATEGORIES
,openMenu
, ...}} 이렇게 할 이유가 없다prevState
쓰세요..
6팀
useContext 단점
- 컨텍스트 개수가 늘어나면 html 태그의 깊이가 무한정으로 깊어진다
- 컨텍스트를 배열로 만들어서 태그를 평평하게 만드는.. 방법도 있긴 하지만 복잡하다
- 리액트에서 기본적으로 제공하긴 하지만 구리다... 퍼포먼스 좋지않음
- Redux도 내부적으론
useContext
를 썼었지만 성능문제로 롤백함 - 다크모드나 테마 등을 만들 때 쓰면 좋겠지만 대규모 데이터에는 부적절함
useState 안에 객체를 넣는 건 좋지 않다
- 리액트에선 객체의 참조값이 바뀌지 않으면 같은 값으로 생각함 ⇒ set할 때 좀 귀찮아짐
- 객체만 넣지 마세요
props 하나로 뭉쳐서 보내기
<testComponent
propA={propA}
propB={propB}
propC={propC}
propD={propD}
propE={propE}
...
/>
const testProp = {propA, propB, propC, propD, propE};
<testComponent propObj={testprop}/>
...
const testComponent = ({propObj}) => {
const {propA, propB, propC, propD, propE} = propObj
// 받아올 때
...
- 이렇게 받아오면 조금 더 간단해진다
useEffect는 useCallback을 대신하지 못하는가?
useEffect
는 의존성을 갖는 변수에 변화가 있으면 실행되는 훅useCallback
은 캐싱에 관련된 훅
객체와 물음표
(testObj?.name)
(testObj.name ? testObj.name : '')
객체의 . 앞에 물음표를 붙이면 오른쪽에 적은 키 값이 존재할 경우키에 대응하는 값을 반환하고, 존재하지 않을 경우 빈 문자열을 반환하는 코드
(testObj.name ?? 'nothing');
(testObj.name ? testObj.name : 'nothing');
비슷한 기능을 하되 키 값이 존재하지 않을 때 빈 문자열 말고 정의한 값을 반환하도록 할 수 있다
기타 내용
localStorage
에서 값 들고오는 코드를 jsx 안에 넣지 말고 함수로 빼는 것이 적합할듯 (리렌더링 방지)- 한 파일에는 한 컴포넌트만 넣자 (2개 이상 넣는 것은 안티패턴)
- 컴포넌트를 선언했다면 해당 컴포넌트를 끌어다 쓰는 코드가 컴포넌트 선언부보다 위에 있는건 좋지 않다 (린터에서 잡아줄듯)
localStorage
안에 값이 없을 땐initialState
를 이용해서 기본값을 적용시켜줍시다- 이러나저러나
store.js
를 쓰면 훨씬 편함 - 날짜 다루는 함수 같은건
utils
같은 파일로 분리하면 가독성에 좋다 props
를 잔뜩 보내는 것보단 하나로 뭉쳐서 전달하는 게 좋아보임useEffect
내의 어마어마하게 긴 내용들 (setState
함수들 잔뜩) ⇒useCallback
각이 보인다- 또한
setState
함수를 카테고리별로useEffect
에 전부 때려넣는 코드는 카테고리 개수가 늘어날 경우 대응하기 매우 힘들어지므로 지양하는 게 좋겠음 toISOString
은 문자열이 깨질 위험이 있다- 컴포넌트 사이즈 최적화가 필요할 듯
7팀
삼항연산 길이 줄이기
isTrue ? {hidden: false} : {hidden: true}
{hidden: !isTrue}
삼항연산자 제일 앞에 있는 조건문이 boolean
을 뱉음을 기억하자..
Recoil 팁
export const testRecoil = atom({
key: '#testRecoil',
default: []
});
- Recoil 변수의 키값에
#
을 붙이면 다른 변수들과 구분되는 소소한 팁 - Recoil 참 깔끔해서 좋아
기타 내용
- 컴포넌트 너무 잘게 쪼개지 않기
localStorage.clear()
은 로컬스토리지의 저장된 값을 다 날리는 기능을 한다- 버튼의 이름 (버튼 위에 적힌 텍스트) 는 굳이
::before
,::after
를 쓰기보단 버튼 태그 내에 적어넣는게 낫다
8팀
useNavigate에 state 넘겨주기 지양
const navigate = useNavigate();
navigate('/test', {'state': state});
- 이런식으론 잘 사용하지 않음
useNavigate
를 사용하는 페이지를 거쳐서 해당 페이지로 넘어가면 문제가 없겠지만, 사용자가 임의로 페이지의 url을 입력해서 넘어가면 넘겨지는 state가 없으므로 오류가 날 확률이 높다- 주소에 인덱스를 넘겨주는 방식 등으로 주소만으로도 페이지가 어떤 값인지 판단하여 컴포넌트 내에서 받아오도록 해야 안전함
태그 attribute를 통해 색상변수 결정하기
$LIGHT_TITLE: #222222;
$LIGHT_BACKGROUND: #bbbbbb;
$DARK_TITLE: #FFFFFF;
$DARK_BACKGROUND: #333333;
:root[color-theme='light'] {
--color-title: #{LIGHT_TITLE};
--color-background: #{LIGHT_BACKGROUND};
}
:root[color-theme='dark'] {
--color-title: #{DARK_TITLE};
--color-background: #{DARK_BACKGROUND};
}
- css의
:root
의사 클래스 (Pseudo class) 는 문서 트리의 가장 루트 요소를 선택한다 - 색상을 지정할 때 위와 같이 설정하면 루트 하위의 모든 요소에 대해 색상 변수에 저 값이 들어가므로 전역적으로 색을 바꿔줄 수 있음
- html 상에 렌더링된 모든 요소가 접근가능함
기타 내용
display: block
은 부모 영역 길이까지 꽉 차지하므로 길이에 제한을 두고 싶다면display: inline-block
사용하기
'프로젝트 > 원티드 프리온보딩' 카테고리의 다른 글
[프리온보딩] 220510 개인과제 #1 (0) | 2022.05.11 |
---|---|
[프리온보딩] 220509 개인과제 #1 시작 (0) | 2022.05.10 |
[프리온보딩] 220503 강의 메모 04 (투두 리스트 예시) (0) | 2022.05.09 |
[프리온보딩] 220508 그룹과제 #1 끝 (0) | 2022.05.09 |
[프리온보딩] 220507 내 과제 리팩토링 2 (0) | 2022.05.08 |
Comments