벤더사에 따라 지원되는 가상 선택자 속성에 일부 차이가 있는 경우가 있다. Chrome, Edge, Safari 등은 -webkit, Firefox는 -moz라는 접두어를 사용한다.
예를 들어서, input[type='date']인 요소에 기본 제공되는 Picker Indicator(옆에 작게 나오는 캘린더 아이콘)는 ::-webkit-calendar-picker-indicator라는 가상 선택자로 접근 가능하고, 기본 제공되는 '연도, 월, 일' 텍스트는 ::-webkit-datetime-edit으로 접근해 커스텀할 수 있다.
이런 벤더 프리픽스를 많이 사용하면 브라우저 간 호환이 되지 않아 특정 브라우저에서 깨지는 크로스 브라우징 이슈가 발생할 수 있다. 가급적 위험 요소가 될 수 있는 벤더 프리픽스는 사용을 최대한 지양하는 것이 좋겠다.
벤더 프리픽스를 사용하지 않는다면, input 요소에 브라우저가 기본 적용하는 스타일을 제어할 방법이 생각보다 없다. 만약에 커스텀하게 Date Picker를 만들고 싶다면, 크로스 브라우징 이슈를 끌어안고 직접 커스텀하기보다는, 잘 만들어진 제공된 라이브러리를 사용하는 것이 좋다.
리액트에서는 React Datepicker라는 라이브러리가 있다. 해당 라이브러리는 DatePicker라는 컴포넌트를 제공하고, 'react-datepicker/dist/react-datepicker.css' 경로에 가면 미리 Date Picker에 대한 기본적인 디자인도 가져와 사용할 수 있다. 스타일은 해당 경로를 import 해오면 바로 적용된다.
DatePicker는 다양한 Props를 제공한다. 굉장히 많은 Props들이 있으며, 필요할 경우 React Datepicker 공식 문서에 가서 확인 후 사용하면 된다.
React Datepicker를 사용할 때, 별도 커스텀이 필요하다면, 화면에 렌더링 된 DOM에 나오는 class 이름을 확인한 후, 개별 CSS로 해당 클래스 이름의 요소에 디자인을 먹일 수 있다. 하지만, CSS를 별도로 커스텀하기 시작하면 라이브러리를 가져와 사용하는 이점이나 안정성 등이 떨어질 수 있기 때문에, 가급적 보수적으로 수정하는 게 좋지 않을까 싶다.
외부 라이브러리를 가져와 사용한 경험이 없어서 아직 낯설다. 앞으로 현업에 가면 꾸준히 많은 도구들을 잘 찾고, 프로젝트에 적용하는 게 일이 될 거다. 잘 연습해 두자.
모던 리액트 Deep Dive
Next.js는 Vercel에서 풀스택 웹 애플리케이션 구축을 위해 만든 리액트 기반 프레임워크다. 태생이 PHP의 대용품으로 등장했다.
Next.js에서는 실제 디렉터리 구조가 곧 URL로 변환되어 라우팅 되는데, 해당 컨셉은 페이스북 팀이 리액트 기반 서버 사이드 렌더링을 위해 고려했던 react-page라는 프로젝트에서 차용한 것이다.
최초 렌더링 될 땐 서버 사이드에서, 이후엔 클라이언트에서 pages/_app.tsx 경로에 있는 rennder() 메서드를 호출한다.
pages/_document.tsx 파일은 없어도 실행에 문제는 없다. 단, _app.tsx가 페이지 전체를 초기화하는 곳이라면, _document.tsx는 애플리케이션의 HTML을 초기화하는 곳이다. 그래서, 둘은 몇 가지 차이점이 있다.
리액트의 root 노드가 아니라, <html>이나 <body>에 DOM 요소를 추가하고 싶으면 _documnet.tsx를 사용한다.
_app.tsx는 경우에 따라 서버-클라이언트 중 한 곳에서 실행되지만, _document.tsx는 무조건 서버에서만 실행된다. 이벤트 핸들러 등록 등 클라이언트에서 hydrate 되는 동작이 포함되면 안 된다.
<head>에 웹 애플리케이션에 공통적인 제목(<title/>)을 사용하려면 _app.tsx 페이지에서 next/head로, 페이지별 제목이 필요하다면 페이지 파일 내부에 <title/>을 넣어준다. next/document의 <Head /> 내부에서는 <title />을 사용할 수 없다.
getServerSideProps, getStaticProps 등 서버에서 사용 가능한 데이터 불러오기 함수는 _document.tsx에서 불러올 수 없다.
정리하면, _app.tsx는 Next.js를 초기화하는 파일이고, _document.tsx는 Next.js로 만드는 웹 사이트의 뼈대가 되는 HTML 설정과 관련된 코드를 추가하는 곳이다.
pages/_error.tsx는 에러 처리 페이지이며, create-next-app이 기본 생성해 주는 파일은 아니다, 즉, 없어도 실행에 문제는 없다.
pages/_error.tsx에는 전역에서 발생하는 에러를 적절하게 처리하기 위한 로직 및 렌더링 화면을 그려주면 된다. 단, 개발 모드에서는 pages/_error.tsx 페이지에 방문할 수 없고 프로덕션으로 빌드해야만 확인이 가능하다.
pages/404.tsx와 pages/505.tsx는 각각 404, 505 에러 페이지를 정의할 수 있는 페이지다. 마찬가지로 필수는 아니며, 없을 시 Next.js에서 제공하는 기본 404 페이지가 사용된다.
_app.tsx, _error.tsx, _document.tsx, 404.tsx, 505.tsx 페이지는 Next.js가 예약어로 관리하는 파일명의 페이지들이다. 이렇게 예약어로 된 파일명을 통해 라우팅 구조를 나타낸 것이 react-pages에서 차용한 컨셉이다.
이외의 페이지는 개발자가 자유롭게 명칭 할 수 있는데, 그중 pages/index.ts는 관례적으로 웹 사이트의 루트 페이지로 사용된다. localhost:3000과 같은 루트 주소를 의미한다.
/pages/hello.tsx라는 경로에 개발자가 생성한 이름의 파일이 있으면 pages와 파일 확장자 tsx가 생략되고 localhost:3000/hello가 라우팅 경로가 된다.
/hello/index.tsx와 /hello.tsx는 같은 경로를 바라본다. index.tsx는 해당 폴더의 진입점이 된다.
/pages/hello/[greeting].tsx처럼 대괄호 []로 묶인 부분은 조커? 같이 동작한다. 사용자가 /pages/hello/hi로 접속하면 greeting은 hi가 되고, /pages/hello/good이 오면 greeting은 good이 된다. []안에 있는 값은 변수처럼 동작한다.
/pages/hi/[...props].tsx는 실제 전개 연산자처럼 동작하며, localhost:3000/hi/hello, localhost:3000/hi/hello/world, localhost:3000/hi/hello/world/foo 등 hi 하위의 모든 주소가 전부 props에 담긴다.
Next.js는 <a> 태그와 유사한 역할을 해주는 next/link 기능을 제공한다. 주로 Link라는 이름의 컴포넌트로 별칭을 붙여서 <Link href='/{경로}'></Link> 형태로 많이 사용한다.
<a> 태그는 렌더링에 필요한 모든 정보를 다 가져오며, 서버 사이드에서 한 번, hydrate 할 때 클라이언트 사이드에서 또 한 번, 이렇게 두 번 렌더링이 일어난다.
하지만 next/link(Link)는 서버 사이드에서 렌더링을 수행한 후, 클라이언트로 와서는 필요한 부분만 렌더링 한다(정확하지 않을 수 있는데, 책을 보고 내가 이해한 내용은 그래서 일단 적어둔다). 그래서, Next.js 애플리케이션을 만들 땐 <a> 태그가 아니라 next/link를 사용해야 한다(그래야 Next.js의 장점을 온전히 살릴 수 있다).
Next.js는 사용자가 볼 수 있는 최초 페이지를 빠르게 제공한다는 장점과, SPA처럼 매끄러운 화면 전환(자연스러운 라우팅)을 구현한다는 두 가지 점을 모두 살리는 식으로 동작한다.
pages에 정의한 파일에서 파일 마지막에 { props: {} }를 반환하는 getServerSideProps 함수를 export 해주고 있는데, 해당 처리가 있어야 그 파일을 서버 사이드 렌더링이 필요한 파일로 간주한다. 빼먹지 말자.
스프린트 참여
서로 다른 사람과 의견을 공유하는 게 참 쉽지 않다는 걸 새롭게 느낀다.
판단하지 않고 수용하고 발산하는 게 잘 안된다. 더 좋은 커뮤니케이터가 되기 위해 노력해서 성장하고 싶다.
세상엔 다양한 사람이 있다. 누구는 이렇다, 또 누구는 저렇다고 판단하지 말자.
겸손하자. 개발하는 사람이 모인 어느 모임에 가더라도 경험, 지식, 기타 등등 아직은 뭐 하나 내가 더 잘난 부분이 없는 게 팩트다.
처음 시작하는 시점부터 도전자의 마음을 갖기로 다짐했다. 성장하는 데 필요한 여러 어려움을 좀 더 집약적으로, 밀도 있게 경험하기로 각오했으니, 잘 안되고 속상한 일이 있어도 겸손한 마음으로 배우자. 결국 결과를 바꾸는 건 태도다.