Udemy <한 입 크기로 잘라먹는 리액트>
- Vite로 빌드한 리액트 프로젝트의
public
과 assets
둘 다 정적 파일을 저장하는 폴더이다. 하지만, 정적 파일 중 이미 파일은 assets
에 저장해야 빌드 시 이미지 최적화가 된다.
assets
에 저장된 이미지 폴더는 빌드 후 배포했을 때 이미지 데이터의 URI를 활용해 브라우저 메모리에 캐싱한다. 캐싱이 되면 한 번 받아온 이미지를 다시 request로 요청해야 할 때 브라우저 메모리에 캐싱된 이미지 URI를 가져와 사용한다.
- 하지만, 항상
assets
폴더에 이미지를 넣는 게 맞진 않다. 정말 많은(또는 무거운) 이미지들이 사용되는 웹 애플리케이션인데 한 번 내려받은 이미지가 브라우저 메모리에 캐싱되면 브라우저의 메모리 사용량이 비대해질 것이다. 적은 양의 이미지라면 모르겠지만, 양이 많아지면 이건 브라우저의 원활한 동작에 문제를 발생시킬 수 있다. 이런 경우엔 정적 이미지 파일을 public
폴더에 저장해서 이미지 최적화를 우회하는 게 필요할 수 있다.
- CSS로
public
폴더에 저장한 폰트를 적용하려면 아래와 같이 @font-face
를 사용해서 폰트 스타일을 지정한 다음, font-family
에 지정한 이름을 CSS 선택자 요소 내부에서 선언해 주면 된다.
@font-face {
font-family: 'NanumPenScript';
src: url('/NanumPenScript-Regular.ttf');
}
...
body {
font-family: 'NanumPenScrtip';
}
- CSS에서
vh
는 'viewport height'를 의미한다. 사용자의 화면 세로 길이를 의미하며, 100vh
라고 설정하면 높이가 뷰포트를 꽉 채우게 된다.
- CSS에서
white-space: nowrap
으로 설정하면 뷰포트 사이즈가 줄어들어도 텍스트가 줄 바꿈 되지 않는다.
useNavigate
로 생성한 Navigation 함수의 두 번째 인자로 객체를 전달해서 옵션을 설정할 수 있다. { replace: true }
로 설정해 주면 라우팅을 하면서 뒤로 가기 적용에서 제외를 시켜준다(뒤로 가기를 해도 이전 페이지로 돌아가지 못하게 한다).
- Navigation 함수에 인자로
-1
을 전달하면 바로 이전 페이지로 이동한다. 아마도 1을 입력하면 앞쪽의 페이지로 이동하게 될 것 같다(history
객체를 사용한 것 같다).
- Navigation 함수는 페이지에 있는 컴포넌트들이 전부 마운트(렌더링) 된 다음에 사용할 수 있다. 순서에 문제가 있다면
useEffect
를 사용해서 마운트 완료 시(의존성 배열로 []
전달) 동작하도록 수정할 수 있다.
- 감정 일기 애플리케이션을 강의를 보며 따라 만들면서 몇 가지 든 생각이 있다.
- Context API는 선언된 위치 하위에서 생성된 Context에 등록된
value
에 쉽게 접근해서 쓸 수 있기 때문에 Props Drilling을 방지하고, 상태를 편하게 관리할 수 있는 유용한 도구임에 틀림없다. 하지만, 언제나 모든 상태를 최상위 컴포넌트에서 정의할 순 없고, 컴포넌트의 계층과 상태를 사용하는 곳에 따라 여러 곳에서 여러 상태가 정의될 수 있다. 이런 경우를 Context API만 가지고 관리하려면 여러 컴포넌트 계층에서 별도로 Context를 새롭게 다 정의를 해줘야 하고, 하위 컴포넌들은 필요에 따라 여러 Context들을 구독해야 하는 상황이 생길 것 같다(실제로 해본 건 아니지만 그럴 것 같다). 그런 식으로 여러 Context가 생기고, 한 컴포넌트에서도 다양한 Context를 구독하는 상황이 생기면, 아무래도 어떤 상태가 어떤 Context에서 어떻게 내려오는 건지를 추적하기가 쉽지 않을 것으로 예상된다. 이런 배경에서 상태 관리를 더욱 쉽게 해주는 다양한 툴들이 등장한 게 아닌가 싶다.
- 컴포넌트들은 자신이 가지고 있는 상태가 변하거나, 또는 상위 부모 컴포넌트가 리렌더링 돼야 하면 함께 리렌더링이 될 수밖에 없다. 즉, 컴포넌트들은 언제나 리렌더링이 될 가능성을 가지고 있다(
useMemo
나 memo
를 사용하면 얘기가 다르긴 하다). 그리고, 컴포넌트가 리렌더링 된다는 것은 함수인 컴포넌트가 다시 실행된다는 것이고, 내부에 정의된 모든 코드들이 다시 실행된다는 것이다. 이것의 사이드 이펙트를 항상 잘 계산해야겠다. 예를 들어, 어떤 상태 변경과 컴포넌트 리렌더링 상황에서도 절대로 바뀌지 않는 함수가 존재할 수 있다(최초 컴포넌트 마운트 시 정의한 함수를 변경 없기 계속 쓰는 경우). 이런 함수는 컴포넌트 리렌더링에 의해 다시 정의될 때마다 예상치 못한 사이드 이펙트를 발생시킬 수 있다. 이런 경우엔 useCallback
을 써주는 것도 방법이고, 아니면 컴포넌트의 외부에 함수를 정의해 주는 것도 방법이 될 수 있다. 아무래도, 컴포넌트 안에 너무 많은 함수가 정의되어 있으면 유지보수나 관리가 어려워질 수 있기 때문에, 적절하게 함수를 컴포넌트 밖으로 빼기 위해 고민을 많이 해야겠다.
- 이외에도 상태를 어디에서 정의할지,
props
로 내려줄 때 어떤 데이터 형태로 내려줄지, 로직을 함수로 분리할 것과 분리하지 않은 것을 어떻게 정할지, 어떤 걸 util
로 빼서 관리할지 등, 개발하면서 고민해야 할 부분이 정말 많은 것 같다. 결국, 안정적이고 확장성 있는 웹 애플리케이션을 만들기 위해 여러 경험과 고민이 수반되어야 한다. 갈 길이 멀다.