HOME / CATALOG / 프로그래밍 & 프랙티스
BEST
프로그래밍 & 프랙티스

모던 리액트 Deep Dive

리액트의 핵심 개념과 동작 원리부터 Next.js까지, 리액트의 모든 것
지은이 김용찬
도서 정보
출간일
2023년 11월 7일
쪽수
952쪽
판형
188*240*38mm
ISBN
9791158394646
시리즈
프로그래밍 & 프랙티스 시리즈_035
정가
48,000원
난이도
도서 소개
저자 소개
목차
예제 코드
정오표

도서 소개

요즘 프런트엔드 개발은 자바스크립트와 리액트부터 시작한다는 말이 있을 정도로 최근 몇 년간 프런트엔드 생태계에서 리액트의 비중은 날이 갈수록 커지고 있습니다.

이 책에서는 0.x 버전의 리액트부터 최신 버전인 18 버전에 이르기까지, 리액트를 둘러싼 다양한 내용을 다루고 있습니다. 리액트는 하나의 온전한 웹 프레임워크를 지향하지 않아 UI 외에 상태 관리나 서버 사이드 렌더링 등 웹 개발의 많은 영역에서 선택의 여지를 남겨뒀으며, 이 때문에 리액트 개발자라면 알아둬야 할 내용이 많습니다.

함수형 컴포넌트와 훅의 동작 원리, 메모이제이션의 필요성과 실제로 메모이제이션되고 있는지 확인하는 방법, 리액트의 상태 관리와 다양한 상태 관리 라이브러리의 동작 방식, 실무에서 널리 쓰이고 있는 Next.js, 그리고 리액트 애플리케이션의 성능을 분석하는 방법까지, 리액트에 관심 있는 개발자라면 이 책을 통해 리액트 앱 개발의 시작부터 끝까지 경험해 보면서 웹 서비스 개발의 즐거움을 만끽하시길 바랍니다.

★ 이 책에서 다루는 내용 ★

  • 리액트의 역사
  • 리액트를 구성하는 기본 개념 - JSX, 함수형/클래스형 컴포넌트부터 메모이제이션까지
  • 리액트의 서버 사이드 렌더링과 서버 컴포넌트
  • 리액트 생태계의 상태 관리 라이브러리
  • 리액트 애플리케이션 디버깅
  • 리액트 17, 18의 변경사항
  • Next.js 12와 13
  • 리액트 기반 웹사이트 성능 분석과 보안 이슈

 

도서 상세 이미지

저자 소개

김용찬

동국대학교 무역학과와 한국과학기술원 기술경영전문대학원 석사과정을 졸업하고 삼성 SDS, 카카오, 트리플(현 인터파크)에서 각각 풀스택 및 프런트엔드 개발자로 근무했다. 현재 네이버 파이낸셜 유저플랫폼에서 프런트엔드 개발자로 근무하고 있다. 그리고 프런트엔드 기술 블로그(https://yceffort.kr)도 함께 운영하고 있다.

목차

  • ▣ 들어가며
  • __왜 리액트인가?
  • __리액트의 역사
  • __2010년대 프런트엔드 개발 환경을 향한 페이스북의 도전
  • __BoltJS의 등장과 한계
  • __페이스북 팀의 대안으로 떠오른 리액트
  • __리액트에 대한 회의적인 의견과 비판
  • __드디어 빛을 보는 리액트
  • __리액트의 현재와 미래
  •  
  • ▣ 01장: 리액트 개발을 위해 꼭 알아야 할 자바스크립트
  • 1.1 자바스크립트의 동등 비교
  • __1.1.1 자바스크립트의 데이터 타입
  • __1.1.2 값을 저장하는 방식의 차이
  • __1.1.3 자바스크립트의 또 다른 비교 공식, Object.is
  • __1.1.4 리액트에서의 동등 비교
  • __1.1.5 정리
  • 1.2 함수
  • __1.2.1 함수란 무엇인가?
  • __1.2.2 함수를 정의하는 4가지 방법
  • __1.2.3 다양한 함수 살펴보기
  • __1.2.4 함수를 만들 때 주의해야 할 사항
  • __1.2.5 정리
  • 1.3 클래스
  • __1.3.1 클래스란 무엇인가?
  • __1.3.2 클래스와 함수의 관계
  • __1.3.3 정리
  • 1.4 클로저
  • __1.4.1 클로저의 정의
  • __1.4.2 변수의 유효 범위, 스코프
  • __1.4.3 클로저의 활용
  • __1.4.4 주의할 점
  • __1.4.5 정리
  • 1.5 이벤트 루프와 비동기 통신의 이해
  • __1.5.1 싱글 스레드 자바스크립트
  • __1.5.2 이벤트 루프란?
  • __1.5.3 태스크 큐와 마이크로 태스크 큐
  • __1.5.4 정리
  • 1.6 리액트에서 자주 사용하는 자바스크립트 문법
  • __1.6.1 구조 분해 할당
  • __1.6.2 전개 구문
  • __1.6.3 객체 초기자
  • __1.6.4 Array 프로토타입의 메서드: map, filter, reduce, forEach
  • __1.6.5 삼항 조건 연산자
  • __1.6.6 정리
  • 1.7 선택이 아닌 필수, 타입스크립트
  • __1.7.1 타입스크립트란?
  • __1.7.2 리액트 코드를 효과적으로 작성하기 위한 타입스크립트 활용법
  • __1.7.3 타입스크립트 전환 가이드
  • __1.7.4 정리
  •  
  • ▣ 02장: 리액트 핵심 요소 깊게 살펴보기
  • 2.1 JSX란?
  • __2.1.1 JSX의 정의
  • __2.1.2 JSX 예제
  • __2.1.3 JSX는 어떻게 자바스크립트에서 변환될까?
  • __2.1.4 정리
  • 2.2 가상 DOM과 리액트 파이버
  • __2.2.1 DOM과 브라우저 렌더링 과정
  • __2.2.2 가상 DOM의 탄생 배경
  • __2.2.3 가상 DOM을 위한 아키텍처, 리액트 파이버
  • __2.2.4 파이버와 가상 DOM
  • __2.2.5 정리
  • 2.3 클래스형 컴포넌트와 함수형 컴포넌트
  • __2.3.1 클래스형 컴포넌트
  • __2.3.2 함수형 컴포넌트
  • __2.3.3 함수형 컴포넌트 vs. 클래스형 컴포넌트
  • __2.3.4 정리
  • 2.4 렌더링은 어떻게 일어나는가?
  • __2.4.1 리액트의 렌더링이란?
  • __2.4.2 리액트의 렌더링이 일어나는 이유
  • __2.4.3 리액트의 렌더링 프로세스
  • __2.4.4 렌더와 커밋
  • __2.4.5 일반적인 렌더링 시나리오 살펴보기
  • __2.4.6 정리
  • 2.5 컴포넌트와 함수의 무거운 연산을 기억해 두는 메모이제이션
  • __2.5.1 주장 1: 섣부른 최적화는 독이다, 꼭 필요한 곳에만 메모이제이션을 추가하자
  • __2.5.2 주장 2: 렌더링 과정의 비용은 비싸다, 모조리 메모이제이션해 버리자
  • __2.5.3 결론 및 정리
  •  
  • ▣ 03장: 리액트 훅 깊게 살펴보기
  • 3.1 리액트의 모든 훅 파헤치기
  • __3.1.1 useState
  • __3.1.2 useEffect
  • __3.1.3 useMemo
  • __3.1.4 useCallback
  • __3.1.5 useRef
  • __3.1.6 useContext
  • __3.1.7 useReducer
  • __3.1.8 useImperativeHandle
  • __3.1.9 useLayoutEffect
  • __3.1.10 useDebugValue
  • __3.1.11 훅의 규칙
  • __3.1.12 정리
  • 3.2 사용자 정의 훅과 고차 컴포넌트 중 무엇을 써야 할까?
  • __3.2.1 사용자 정의 훅
  • __3.2.2 고차 컴포넌트
  • __3.2.3 사용자 정의 훅과 고차 컴포넌트 중 무엇을 써야 할까?
  • __3.2.4 정리
  •  
  • ▣ 04장: 서버 사이드 렌더링
  • 4.1 서버 사이드 렌더링이란?
  • __4.1.1 싱글 페이지 애플리케이션의 세상
  • __4.1.2 서버 사이드 렌더링이란?
  • __4.1.3 SPA와 SSR을 모두 알아야 하는 이유
  • __4.1.4 정리
  • 4.2 서버 사이드 렌더링을 위한 리액트 API 살펴보기
  • __4.2.1 renderToString
  • __4.2.2 renderToStaticMarkup
  • __4.2.3 renderToNodeStream
  • __4.2.4 renderToStaticNodeStream
  • __4.2.5 hydrate
  • __4.2.6 서버 사이드 렌더링 예제 프로젝트
  • __4.2.7 정리
  • 4.3 Next.js 톺아보기
  • __4.3.1 Next.js란?
  • __4.3.2 Next.js 시작하기
  • __4.3.3 Data Fetching
  • __4.3.4 스타일 적용하기
  • __4.3.5 _app.tsx 응용하기
  • __4.3.6 next.config.js 살펴보기
  • __4.3.7 정리
  •  
  • ▣ 05장: 리액트와 상태 관리 라이브러리
  • 5.1 상태 관리는 왜 필요한가?
  • __5.1.1 리액트 상태 관리의 역사
  • __5.1.2 정리
  • 5.2 리액트 훅으로 시작하는 상태 관리
  • __5.2.1 가장 기본적인 방법: useState와 useReducer
  • __5.2.2 지역 상태의 한계를 벗어나보자: useState의 상태를 바깥으로 분리하기
  • __5.2.3 useState와 Context를 동시에 사용해 보기
  • __5.2.4 상태 관리 라이브러리 Recoil, Jotai, Zustand 살펴보기
  • __5.2.5 정리
  •  
  • ▣ 06장: 리액트 개발 도구로 디버깅하기
  • 6.1 리액트 개발 도구란?
  • 6.2 리액트 개발 도구 설치
  • 6.3 리액트 개발 도구 활용하기
  • __6.3.1 컴포넌트
  • __6.3.2 프로파일러
  • 6.4 정리
  •  
  • ▣ 07장: 크롬 개발자 도구를 활용한 애플리케이션 분석
  • 7.1 크롬 개발자 도구란?
  • 7.2 요소 탭
  • __7.2.1 요소 화면
  • __7.2.2 요소 정보
  • 7.3 소스 탭
  • 7.4 네트워크 탭
  • 7.5 메모리 탭
  • __7.5.1 자바스크립트 인스턴스 VM 선택
  • __7.5.2 힙 스냅샷
  • __7.5.3 타임라인 할당 계측
  • __7.5.4 할당 샘플링
  • 7.6 Next.js 환경 디버깅하기
  • __7.6.1 Next.js 프로젝트를 디버그 모드로 실행하기
  • __7.6.2 Next.js 서버에 트래픽 유입시키기
  • __7.6.3 Next.js의 메모리 누수 지점 확인하기
  • 7.7 정리
  •  
  • ▣ 08장: 좋은 리액트 코드 작성을 위한 환경 구축하기
  • 8.1 ESLint를 활용한 정적 코드 분석
  • __8.1.1 ESLint 살펴보기
  • __8.1.2 eslint-plugin과 eslint-config
  • __8.1.3 나만의 ESLint 규칙 만들기
  • __8.1.4 주의할 점
  • __8.1.5 정리
  • 8.2 리액트 팀이 권장하는 리액트 테스트 라이브러리
  • __8.2.1 React Testing Library란?
  • __8.2.2 자바스크립트 테스트의 기초
  • __8.2.3 리액트 컴포넌트 테스트 코드 작성하기
  • __8.2.4 사용자 정의 훅 테스트하기
  • __8.2.5 테스트를 작성하기에 앞서 고려해야 할 점
  • __8.2.6 그 밖에 해볼 만한 여러 가지 테스트
  • __8.2.7 정리
  •  
  • ▣ 09장: 모던 리액트 개발 도구로 개발 및 배포 환경 구축하기
  • 9.1 Next.js로 리액트 개발 환경 구축하기
  • __9.1.1 create-next-app 없이 하나씩 구축하기
  • __9.1.2 tsconfig.json 작성하기
  • __9.1.3 next.config.js 작성하기
  • __9.1.4 ESLint와 Prettier 설정하기
  • __9.1.5 스타일 설정하기
  • __9.1.6 애플리케이션 코드 작성
  • __9.1.7 정리
  • 9.2 깃허브 100% 활용하기
  • __9.2.1 깃허브 액션으로 CI 환경 구축하기
  • __9.2.2 직접 작성하지 않고 유용한 액션과 깃허브 앱 가져다 쓰기
  • __9.2.3 깃허브 Dependabot으로 보안 취약점 해결하기
  • __9.2.4 정리
  • 9.3 리액트 애플리케이션 배포하기
  • __9.3.1 Netlify
  • __9.3.2 Vercel
  • __9.3.3 DigitalOcean
  • __9.3.4 정리
  • 9.4 리액트 애플리케이션 도커라이즈하기
  • __9.4.1 리액트 앱을 도커라이즈하는 방법
  • __9.4.2 도커로 만든 이미지 배포하기
  • __9.4.3 정리
  •  
  • ▣ 10장: 리액트 17과 18의 변경 사항 살펴보기
  • 10.1 리액트 17 버전 살펴보기
  • __10.1.1 리액트의 점진적인 업그레이드
  • __10.1.2 이벤트 위임 방식의 변경
  • __10.1.3 import React from ‘reac’가 더 이상 필요 없다: 새로운 JSX transform
  • __10.1.4 그 밖의 주요 변경 사항
  • __10.1.5 정리
  • 10.2 리액트 18 버전 살펴보기
  • __10.2.1 새로 추가된 훅 살펴보기
  • __10.2.2 react-dom/client
  • __10.2.3 react-dom/server
  • __10.2.4 자동 배치(Automatic Batching)
  • __10.2.5 더욱 엄격해진 엄격 모드
  • __10.2.6 Suspense 기능 강화
  • __10.2.7 인터넷 익스플로러 지원 중단에 따른 추가 폴리필 필요
  • __10.2.8 그 밖에 알아두면 좋은 변경사항
  • __10.2.9 정리
  •  
  • ▣ 11장: Next.js 13과 리액트 18
  • 11.1 app 디렉터리의 등장
  • __11.1.1 라우팅
  • 11.2 리액트 서버 컴포넌트
  • __11.2.1 기존 리액트 컴포넌트와 서버 사이드 렌더링의 한계
  • __11.2.2 서버 컴포넌트란?
  • __11.2.3 서버 사이드 렌더링과 서버 컴포넌트의 차이
  • __11.2.4 서버 컴포넌트는 어떻게 작동하는가?
  • 11.3 Next.js에서의 리액트 서버 컴포넌트
  • __11.3.1 새로운 fetch 도입과 getServerSideProps, getStaticProps, getInitial Props의 삭제
  • __11.3.2 정적 렌더링과 동적 렌더링
  • __11.3.3 캐시와 mutating, 그리고 revalidating
  • __11.3.4 스트리밍을 활용한 점진적인 페이지 불러오기
  • 11.4 웹팩의 대항마, 터보팩의 등장(beta)
  • 11.5 서버 액션(alpha)
  • __11.5.1 form의 action
  • __11.5.2 input의 submit과 image의 formAction
  • __11.5.3 startTransition과의 연동
  • __11.5.4 server mutation이 없는 작업
  • __11.5.5 서버 액션 사용 시 주의할 점
  • 11.6 그 밖의 변화
  • 11.7 Next.js 13 코드 맛보기
  • __11.7.1 getServerSideProps와 비슷한 서버 사이드 렌더링 구현해 보기
  • __11.7.2 getStaticProps와 비슷한 정적인 페이지 렌더링 구현해 보기
  • __11.7.3 로딩, 스트리밍, 서스펜스
  • 11.8 정리 및 주의사항
  •  
  • ▣ 12장: 모든 웹 개발자가 관심을 가져야 할 핵심 웹 지표
  • 12.1 웹사이트와 성능
  • 12.2 핵심 웹 지표란?
  • 12.3 최대 콘텐츠풀 페인트(LCP)
  • __12.3.1 정의
  • __12.3.2 의미
  • __12.3.3 예제
  • __12.3.4 기준 점수
  • __12.3.5 개선 방안
  • 12.4 최초 입력 지연(FID)
  • __12.4.1 정의
  • __12.4.2 의미
  • __12.4.3 예제
  • __12.4.4 기준 점수
  • __12.4.5 개선 방안
  • 12.5 누적 레이아웃 이동(CLS)
  • __12.5.1 정의
  • __12.5.2 의미
  • __12.5.3 예제
  • __12.5.4 기준 점수
  • __12.5.5 개선 방안
  • __12.5.6 핵심 웹 지표는 아니지만 성능 확인에 중요한 지표들
  • 12.6 정리
  •  
  • ▣ 13장: 웹페이지의 성능을 측정하는 다양한 방법
  • 13.1 애플리케이션에서 확인하기
  • __13.1.1 create-react-app
  • __13.1.2 create-next-app
  • 13.2 구글 라이트하우스
  • __13.2.1 구글 라이트하우스 - 탐색 모드
  • __13.2.2 구글 라이트하우스 - 기간 모드
  • __13.2.3 구글 라이트하우스 – 스냅샷
  • 13.3 WebPageTest
  • __13.3.1 Performance Summary
  • __13.3.2 Opportunities & Experiments
  • __13.3.3 Filmstrip
  • __13.3.4 Details
  • __13.3.5 Web Vitals
  • __13.3.6 Optimizations
  • __13.3.7 Content
  • __13.3.8 Domains
  • __13.3.9 Console Log
  • __13.3.10 Detected Technologies
  • __13.3.11 Main-thread Processing
  • __13.3.12 Lighthouse Report
  • __13.3.13 기타
  • 13.4 크롬 개발자 도구
  • __13.4.1 성능 통계
  • __13.4.2 성능
  • 13.5 정리
  •  
  • ▣ 14장: 웹사이트 보안을 위한 리액트와 웹페이지 보안 이슈
  • 14.1 리액트에서 발생하는 크로스 사이트 스크립팅(XSS)
  • __14.1.1 dangerouslySetInnerHTML prop
  • __14.1.2 useRef를 활용한 직접 삽입
  • __14.1.3 리액트에서 XSS 문제를 피하는 방법
  • 14.2 getServerSideProps와 서버 컴포넌트를 주의하자
  • 14.3 태그의 값에 적절한 제한을 둬야 한다
  • 14.4 HTTP 보안 헤더 설정하기
  • __14.4.1 Strict-Transport-Security
  • __14.4.2 X-XSS-Protection
  • __14.4.3 X-Frame-Options
  • __14.4.4 Permissions-Policy
  • __14.4.5 X-Content-Type-Options
  • __14.4.6 Referrer-Policy
  • __14.4.7 Content-Security-Policy
  • __14.4.8 보안 헤더 설정하기
  • __14.4.9 보안 헤더 확인하기
  • 14.5 취약점이 있는 패키지의 사용을 피하자
  • 14.6 OWASP Top 10
  • 14.7 정리
  •  
  • ▣ 15장: 마치며
  • 15.1 리액트 프로젝트를 시작할 때 고려해야 할 사항
  • __15.1.1 유지보수 중인 서비스라면 리액트 버전을 최소 16.8.6에서 최대 17.0.2로 올려두자
  • __15.1.2 인터넷 익스플로러 11 지원을 목표한다면 각별히 더 주의를 기한다
  • __15.1.3 서버 사이드 렌더링 애플리케이션을 우선적으로 고려한다
  • __15.1.4 상태 관리 라이브러리는 꼭 필요할 때만 사용한다
  • __15.1.5 리액트 의존성 라이브러리 설치를 조심한다
  • 15.2 언젠가 사라질 수도 있는 리액트
  • __15.2.1 리액트는 그래서 정말 완벽한 라이브러리인가?
  • __15.2.2 오픈소스 생태계의 명과 암
  • __15.2.3 제이쿼리, AngularJS, 리액트, 그리고 다음은 무엇인가?
  • __15.2.4 웹 개발자로서 가져야 할 유연한 자세

정오표

2쇄

  • 54쪽, 예제 코드의 밑에서 8번째 줄

    console.log('짐을 싣습니다.')

    ==>

    console.log('짐을 싣습니다!')
  • 62쪽, 본문 밑에서 6번째 줄

    그리고 이러한 스코프는 동적으로 결정된다는

    ==>

    그리고 이러한 스코프는 정적으로 결정된다는

  • 64쪽, 페이지 상단 예제 코드의 마지막 줄

    console.log(c.counter()) // 2

    ==>

    console.log(c.counter()) // counter에 접근! // 2
  • 64쪽, 그림 1.4를 다음 그림으로 교체

    그림 1.4

  • 74쪽, 예제 코드의 밑에서 5번째 줄

    setTimeout(bar(), 0) // setTimeout만 추가했다.

    ==>

    setTimeout(bar, 0) // setTimeout만 추가했다.
  • 124쪽, 페이지 상단 코드의 3~13번째 줄(ComponentC를 삭제)

    function ComponentC() {
      return <A:B.C></A:B.C>
    }
    
    function ComponentD() {
      return <$></$>
    }
    
    function ComponentE() {
      return <_></_>
    }
    

    ==>

    function ComponentC() {
      return <$></$>
    }
    
    function ComponentD() {
      return <_></_>
    }
  • 126쪽, 첫 번째 예제 코드의 1~6번째 줄

    import * as Babel from '@babel/standalone'
    
    Babel.registerPlugin(
      '@babel/plugin-transform-react-jsx',
      require('@babel/plugin-transform-react-jsx'),
    )

    ==>

    import * as Babel from "@babel/standalone";
    import transformJSX from "@babel/plugin-transform-react-jsx";
    
    Babel.registerPlugin("@babel/plugin-transform-react-jsx", transformJSX);
  • 141쪽, 페이지 중간 번호 목록의 7~13번 항목을 다음 내용으로 교체

    7. D1은 자식이 없으므로 completeWork()가 수행된다. 자식은 없으므로 형제인 D2로 넘어간다.
    8. D2의 beginWork()가 수행된다.
    9. D2는 자식이 없으므로 completeWork()가 수행된다.
    10. D2는 자식도, 더 이상의 형제도 없으므로 위로 이동해 C1, B2 순으로 completeWork()를 호출한다.
    11. B2의 형제인 B3으로 이동해 beginWork()를 수행한다.
    12. B3의 completeWork()가 수행되면 반환해 상위로 타고 올라간다.
    13. A1의 completeWork()가 수행된다.
    14. 루트 노드가 완성되는 순간, 최종적으로 commitWork()가 수행되고 이 중에 변경 사항을 비교해 업데이트가 필요한 변경 사항이 DOM에 반영된다.
  • 154쪽, 페이지 하단 예제 코드의 5번째 줄

    if (props.name !== state.name) {

    ==>

    if (nextProps.name !== prevState.name) {
  • 158쪽, 본문 밑에서 5번째 줄(소제목)

    componentDidCatch

    ==>

    componentDidCatch()

  • 161쪽, 박스 내 2번째 줄

    즉, window.eonerror

    ==>

    즉, window.onerror

  • 196쪽, 본문 13번째 줄

    그렇다면 게으른 최적화는 언제 쓰는 것이 좋을까?

    ==>

    그렇다면 게으른 초기화는 언제 쓰는 것이 좋을까?

  • 208쪽, 첫 번째 예제 코드의 밑에서 5번째 줄

    // shouldIgnore를 이용해 useState의 두 번째 인수를 실행을 막는 것뿐만 아니라

    ==>

    // shouldIgnore를 이용해 setData의 실행을 막는 것 뿐만 아니라
  • 318쪽, 예제 코드의 7~11번째 줄

    if (!post) {
      redirect: {
        destination: '/404'
      }
    }

    ==>

    if (!post) {
      return {
        redirect: {
          destination: '/404'
        }
      }
    }
  • 322쪽, 페이지 상단 예제 코드의 7번째 줄

    import 'normalize.css/normalize.css'

    ==>

    import 'node_modules/normalize.css'
  • 331쪽, 본문 7번째 줄

    • 로그: [클라이언트] /test/GSSP에서 undefined를 요청

    ==>

    • 로그: [클라이언트] /test/GIP에서 undefined를 요청
  • 334쪽, 페이지 상단 예제 코드의 3번째 줄(코드 주석)

    // /tag/foo => /tag/foo/pages/1

    ==>

    // /tag/foo => /tags/foo/pages/1
  • 334쪽, 페이지 상단 예제 코드의 9번째 줄(코드 주석)

    // /tag/foo => /tags/foo/pages/1

    ==>

    // /tag/foo/page/1 => /tags/foo/pages/1
  • 334쪽, 페이지 상단 예제 코드의 15번째 줄(코드 주석)

    // /tag/foo/pages/something => /tags/foo/pages/1

    ==>

    // /tags/foo/pages/something => /tags/foo/pages/1
  • 338쪽, 본문 7번째 줄

    이를 기반으로 한 라이브러인

    ==>

    이를 기반으로 한 라이브러리인

  • 534쪽, 본문 16번째 줄

    만약 이 옵션이 켜져 있다면 d.ts에 에러가 있다면 에러를 발생시킨다.

    ==>

    만약 이 옵션에 false를 주면 에러를 발생시킨다.

  • 660쪽, 예제 코드의 2번째 줄

    // legacy/createLegacyRoot를 promise로 layzy하게 불러온다.

    ==>

    // legacy/createLegacyRoot를 promise로 lazy하게 불러온다.
  • 698쪽, 본문 2번째 줄

    renderToPipeableStream 대신에 이 메서드를 사용해야 한다.

    ==>

    renderToNodeStream 대신에 이 메서드를 사용해야 한다.

  • 710쪽, 페이지 상단 예제 코드를 다음 코드로 교체

    function ProfilePage() {
      // initialResource는 Promise로 데이터를 불러오는 데 어느 정도 시간이 필요함
      const [resource, setResource] = useState(initialResource)
      return (
        <Suspense fallback={<h1>Loading posts...</h1>}>
          <Sibling name="two" />
          <ProfileTimeline resource={resource} />
        </Suspense>
      )
    }
  • 732쪽, 본문 3번째 줄

    서버에서 클라이언트에서 전송되는 결과물 또한

    ==>

    서버에서 클라이언트로 전송되는 결과물 또한

  • 809쪽, 본문 5번째 줄

    만약 사용자 뷰포트 너비에 맞춰 다른 이미지를 제공하고 경우,

    ==>

    만약 사용자 뷰포트 너비에 맞춰 다른 이미지를 제공하고 싶은 경우,

  • 822쪽, 본문 밑에서 3번째 줄

    페이지 내 콘텐츠가 표시되는 되는 시점

    ==>

    페이지 내 콘텐츠가 표시되는 시점

  • 843쪽, 본문 4~5번째 줄 삭제

    다음으로, 최초 뷰포트 영역에서 가장 눈에 띄는 부분 중 하나는 대문 사진인데, 이 영역은 리소스 중 65번째로 요청된다.

    ==>

    (삭제)

초판 1쇄

  • '함수형/클래스형 컴포넌트' 표기

    본문 내에서 사용된 '함수형 컴포넌트(functional component)' 표기는 함수형 프로그래밍으로 혼동할 가능성이 있고 리액트 내에서도 공식적으로 사용되지 않는 표현이라 본문 내에서도 모두 '함수 컴포넌트(function component)'로 변경합니다. '클래스형 컴포넌트'도 일괄적으로 '클래스 컴포넌트'로 변경합니다.

  • 목차 xxiii 페이지의 10.1.3절 제목

    10.1.3 import React from ‘reac’가 더 이상 필요 없다: 새로운 JSX transform

    ==>

    10.1.3 import React from ‘react’가 더 이상 필요 없다: 새로운 JSX transform

  • 22쪽, 본문 밑에서 5번째 줄

    참(true)과 거짓(boolean)만을

    ==>

    참(true)과 거짓(false)만을

  • 24쪽, 페이지 중간 예제 코드를 다음 예제로 교체

    const 이진수_2 = 0b10 // 2진수(binary) 2
    이진수_2 == 2 // true
    
    const 팔진수_8 = 0o10 // 8진수(octal) 8
    팔진수_8 == 8 // true
    
    const 십육진수_16 = 0x10 // 16진수(hexadecimal) 16
    십육진수_16 == 16 // true
  • 29쪽, 본문 6번째 줄

    (type casting)을 한 후에 변경한다.

    ==>

    (type casting)을 한 후에 비교한다.

  • 32쪽, 페이지 하단 예제의 5번째 줄

    return <h1>{hello}</h1>

    ==>

    return <h1>{props.hello}</h1>
  • 37쪽, 두 번째 예제의 마지막 줄

    add(10, 24) // Uncaught TypeError: add is not defined

    ==>

    add(10, 24) // Uncaught ReferenceError: add is not defined
  • 41쪽, 본문 3번째 줄

    즉, 별도의 작업을 추가로 하지 않고 this를 접근할 수 있는 방법이

    ==>

    즉, 별도의 작업을 추가로 하지 않고 this에 접근할 수 있는 방법이

  • 47쪽, 본문 밑에서 8번째 줄

    라이브러리를 마주한다면 클래형 컴포넌트를

    ==>

    라이브러리를 마주한다면 클래스 컴포넌트를

  • 53쪽, 예제 코드의 밑에서 2번째 줄

    myCar.hello() // TypeError: myCar.hello is not a function

    ==>

    myCar.hello() // Uncaught TypeError: myCar.hello is not a function
  • 54쪽, 예제 코드의 밑에서 8번째 줄

    console.log('짐을 싣습니다.')

    ==>

    console.log('짐을 싣습니다!')
  • 54쪽, 예제 코드의 밑에서 3번째 줄

    myCar.honk() // 경적을 울립니다!

    ==>

    myCar.honk() // 자동차 경적을 울립니다!
  • 55쪽, 페이지 상단 예제 코드의 첫 번째 줄

    truck.honk() // 경적을 울립니다!

    ==>

    truck.honk() // 트럭 경적을 울립니다!
  • 62쪽, 본문 밑에서 6번째 줄

    그리고 이러한 스코프는 동적으로 결정된다는

    ==>

    그리고 이러한 스코프는 정적으로 결정된다는

  • 64쪽, 페이지 상단 예제 코드의 마지막 줄

    console.log(c.counter()) // 2

    ==>

    console.log(c.counter()) // counter에 접근! // 2
  • 64쪽, 그림 1.4를 다음 그림으로 교체

    그림 1.4

  • 74쪽, 예제 코드의 밑에서 5번째 줄

    setTimeout(bar(), 0) // setTimeout만 추가했다.

    ==>

    setTimeout(bar, 0) // setTimeout만 추가했다.
  • 83쪽, 첫 번째 예제 코드를 다음 코드로 교체

    const object = {
      a: 1,
      b: 2,
      c: 3,
      d: 4,
      e: 5,
    }
    
    const { a, b, c, ...objectRest } = object
    // a 1
    // b 2
    // c 3
    // objectRest = {d: 4, e: 5}
  • 83쪽, 두 번째 예제 코드를 다음 코드로 교체

    const object = {
      a: 1,
      b: 2,
    }
    
    const { a: first, b: second } = object
    // first 1
    // second 2
  • 89쪽, 본문 첫 번째 줄

    값 할당이 있다면 전개 구문이 할당한 값을 덮어쓰겠지만

    ==>

    값 할당이 있다면 할당한 값이 이전에 전개했던 구문 값을 덮어쓰겠지만

  • 99쪽, 2번째 예제 코드의 5번째 줄

    return 5 / 2

    ==>

    return a / b
  • 102쪽, 2번째 예제 코드의 3번째 줄

    callback()

    ==>

    callback()
    return
  • 118쪽, 본문 6번째 줄

    - 예: <JSXElement />

    ==>

    - 예: </JSXElement>
  • 123쪽, 예제 코드의 6번째 줄

    // 속성과 속성을 넣을 수 있다.

    ==>

    // 속성과 속성값을 넣을 수 있다.
  • 124쪽, 페이지 상단 코드의 3~13번째 줄(ComponentC를 삭제)

    function ComponentC() {
      return <A:B.C></A:B.C>
    }
    
    function ComponentD() {
      return <$></$>
    }
    
    function ComponentE() {
      return <_></_>
    }
    

    ==>

    function ComponentC() {
      return <$></$>
    }
    
    function ComponentD() {
      return <_></_>
    }
  • 126쪽, 첫 번째 예제 코드의 1~6번째 줄

    import * as Babel from '@babel/standalone'
    
    Babel.registerPlugin(
      '@babel/plugin-transform-react-jsx',
      require('@babel/plugin-transform-react-jsx'),
    )

    ==>

    import * as Babel from "@babel/standalone";
    import transformJSX from "@babel/plugin-transform-react-jsx";
    
    Babel.registerPlugin("@babel/plugin-transform-react-jsx", transformJSX);
  • 133쪽, 본문 밑에서 7번째 줄

    과거 리액트 리액트의 조정 알고리즘은

    ==>

    과거 리액트의 조정 알고리즘은

  • 141쪽, 페이지 중간 번호 목록의 7~13번 항목을 다음 내용으로 교체

    7. D1은 자식이 없으므로 completeWork()가 수행된다. 자식은 없으므로 형제인 D2로 넘어간다.
    8. D2의 beginWork()가 수행된다.
    9. D2는 자식이 없으므로 completeWork()가 수행된다.
    10. D2는 자식도, 더 이상의 형제도 없으므로 위로 이동해 C1, B2 순으로 completeWork()를 호출한다.
    11. B2의 형제인 B3으로 이동해 beginWork()를 수행한다.
    12. B3의 completeWork()가 수행되면 반환해 상위로 타고 올라간다.
    13. A1의 completeWork()가 수행된다.
    14. 루트 노드가 완성되는 순간, 최종적으로 commitWork()가 수행되고 이 중에 변경 사항을 비교해 업데이트가 필요한 변경 사항이 DOM에 반영된다.
  • 151쪽, 페이지 중간 예제코드의 2~3번째 줄

    // false인 경우, 즉 props의 title이 같거나 state의 input이 같은 경우에는
    // 컴포넌트를 업데이트하지 않는다.

    ==>

    // true인 경우, 즉 props의 title이 같지 않거나 state의 input이 같지 않은 경우에는
    // 컴포넌트를 업데이트한다. 이외의 경우에는 업데이트하지 않는다.
  • 154쪽, 페이지 하단 예제 코드의 5번째 줄

    if (props.name !== state.name) {

    ==>

    if (nextProps.name !== prevState.name) {
  • 158쪽, 본문 밑에서 5번째 줄(소제목)

    componentDidCatch

    ==>

    componentDidCatch()

  • 161쪽, 박스 내 2번째 줄

    즉, window.eonerror

    ==>

    즉, window.onerror

  • 174쪽, 본문 밑에서 2번째 줄

    통일한 key를 가지고 있는

    ==>

    동일한 key를 가지고 있는

  • 175쪽, 본문 4번째 줄(중복된 단락 중 첫 번째 단락 삭제)

    만약 반대로 key에 <Child index={Math.random()} />과 같이 매 렌더링마다 변하는 임의의 값을 넣는다고 가정해 보자. 이는 리렌더링이 일어날 때마다 sibling 컴포넌트를 명확히 구분할 수 없어 Child가 memo로 선언됐더라도 매번 리렌더링이 일어나게 된다. 즉, key의 변화는 리렌더링을 야기한다.

    만약 반대로 <Child key={Math.random()} />과 같이 렌더링할 때마다 변하는 임의의 값을 key에 넣는다고 가정해 보자. 이때는 리렌더링이 일어날 때마다 sibling 컴포넌트를 명확히 구분할 수 없으므로 Child는 memo로 선언됐더라도 매번 리렌더링이 일어나게 된다. 즉, key의 변화는 리렌더링을 야기한다. 이러한 특징을 이용하면 key를 활용해 강제로 리렌더링을 일으키는 것이 가능해진다.

    ==>

    (삭제)

    만약 반대로 <Child key={Math.random()} />과 같이 렌더링할 때마다 변하는 임의의 값을 key에 넣는다고 가정해 보자. 이때는 리렌더링이 일어날 때마다 sibling 컴포넌트를 명확히 구분할 수 없으므로 Child는 memo로 선언됐더라도 매번 리렌더링이 일어나게 된다. 즉, key의 변화는 리렌더링을 야기한다. 이러한 특징을 이용하면 key를 활용해 강제로 리렌더링을 일으키는 것이 가능해진다.

  • 196쪽, 본문 13번째 줄

    그렇다면 게으른 최적화는 언제 쓰는 것이 좋을까?

    ==>

    그렇다면 게으른 초기화는 언제 쓰는 것이 좋을까?

  • 202쪽, 본문 8번째 줄

    반면 직접 실행은 컴포넌트가 렌더링되는 도중에 실행된다. 따라서 1번과는 달리

    ==>

    반면 1번과 같이 함수 내부에서의 직접 실행은 컴포넌트가 렌더링되는 도중에 실행된다. 따라서 2번과는 달리

  • 203쪽, 예제 코드의 16~25번째 줄

    // 변경이 일어났다면 첫 번째 인수인 콜백 함수를 실행한다.
    if (isDependenciesChanged) {
        callback()
    }
    
    // 현재 의존성을 훅에 다시 저장한다.
    hooks[index] = dependencies
    
    // 다음 훅이 일어날 때를 대비하기 위해 index를 추가한다.
    index++

    ==>

    // 변경이 일어났다면 첫 번째 인수인 콜백 함수를 실행한다.
    if (isDependenciesChanged) {
        callback()
    
        // 다음 훅이 일어날 때를 대비하기 위해 index를 추가한다.
        index++
    
        // 현재 의존성을 훅에 다시 저장한다.
        hooks[index] = dependencies
    }
  • 208쪽, 첫 번째 예제 코드의 밑에서 5번째 줄

    // shouldIgnore를 이용해 useState의 두 번째 인수를 실행을 막는 것뿐만 아니라

    ==>

    // shouldIgnore를 이용해 setData의 실행을 막는 것 뿐만 아니라
  • 219쪽, 페이지 하단 예제 코드의 4번째 줄

    <D props={something}>

    ==>

    <D props={something} />
  • 220쪽, 예제 코드의 첫 번째 줄

    const Context = createContext<{ hello: string } | undefined>()

    ==>

    const Context = createContext<{ hello: string } | undefined>(undefined)
  • 273쪽, 본문 밑에서 2번째 줄

    Node.js 환경에서만 사용할 수 있다.

    ==>

    Node.js나 Deno, Bun 같은 서버 환경에서만 사용할 수 있다.

  • 294쪽, 본문 2번째 줄

    만든 리액트 기반 서버 사이드 렌더링 프레임워크다.

    ==>

    만든 풀스택 웹 애플리케이션을 구축하기 위한 리액트 기반 프레임워크다.

  • 299쪽, 본문 9번째 줄

    오직 document.tsx에서만 사용할 수 있다.

    ==>

    오직 _document.tsx에서만 사용할 수 있다.

  • 301쪽, 본문 밑에서 6번째 줄

    gretting 변수에는 각각 1, greetting이라는 값이 들어온다.

    ==>

    greeting 변수에는 각각 1, greeting이라는 값이 들어온다.

  • 314쪽, 본문 5번째 줄

    사용자가 미리 빌드하지 않은 페이지에 접근할 경, 빌드되기 전까지는

    ==>

    사용자가 미리 빌드하지 않은 페이지에 접근할 경우, 빌드되기 전까지는

  • 318쪽, 예제 코드의 7~11번째 줄

    if (!post) {
      redirect: {
        destination: '/404'
      }
    }

    ==>

    if (!post) {
      return {
        redirect: {
          destination: '/404'
        }
      }
    }
  • 320쪽, 본문 밑에서 4번째 줄

    따라서 서버와 클라이언 모두에서

    ==>

    따라서 서버와 클라이언트 모두에서

  • 322쪽, 페이지 상단 예제 코드의 7번째 줄

    import 'normalize.css/normalize.css'

    ==>

    import 'node_modules/normalize.css'
  • 331쪽, 본문 7번째 줄

    • 로그: [클라이언트] /test/GSSP에서 undefined를 요청

    ==>

    • 로그: [클라이언트] /test/GIP에서 undefined를 요청
  • 331쪽, 페이지 하단 예제 코드의 2번째 줄(코드 추가)

    const {

    ==>

    const appProps = await App.getInitialProps(context)
    const {
  • 334쪽, 페이지 상단 예제 코드의 3번째 줄(코드 주석)

    // /tag/foo => /tag/foo/pages/1

    ==>

    // /tag/foo => /tags/foo/pages/1
  • 334쪽, 페이지 상단 예제 코드의 9번째 줄(코드 주석)

    // /tag/foo => /tags/foo/pages/1

    ==>

    // /tag/foo/page/1 => /tags/foo/pages/1
  • 334쪽, 페이지 상단 예제 코드의 15번째 줄(코드 주석)

    // /tag/foo/pages/something => /tags/foo/pages/1

    ==>

    // /tags/foo/pages/something => /tags/foo/pages/1
  • 338쪽, 본문 7번째 줄

    이를 기반으로 한 라이브러인

    ==>

    이를 기반으로 한 라이브러리인

  • 343쪽, 본문 4번째 줄

    하고자 하는 일에 비에

    ==>

    하고자 하는 일에 비해

  • 363쪽, 예제 코드의 18번째 줄

    console.log('Counter Rendered')

    ==>

    console.log('TextEditor Rendered')
  • 372쪽, 본문 밑에서 5번째 줄

    Recoil과 Jotai는 Context Provider,

    ==>

    Recoil과 Jotai는 Context Provider,

  • 387쪽, 예제 코드의 6~19번째 줄

    // Pull the atoms's state from the store into React state.
    const [[version, valueFromReducer, atomFromReducer], rerenderIfChanged] =
      ((prev, nextVersion) => {
        const nextValue = getAtomValue(nextVersion)
        if (Object.is(prev[1], nextValue) && prev[2] === atom) {
          return prev // bail out
        }
        return [nextVersion, nextValue, atom]
      },
      versionFromProvider,
      (initialVersion) => {
        const initialValue = getAtomValue(initialVersion)
        return [initialVersion, initialValue, atom]
      })

    ==>

    // Pull the atoms's state from the store into React state.
    const [[version, valueFromReducer, atomFromReducer], rerenderIfChanged] =
      useReducer<
        Reducer<
          readonly [VersionObject | undefined, Awaited<Value>, Atom<Value>],
          VersionObject | undefined
        >,
        VersionObject | undefined
      >(
        (prev, nextVersion) => {
          const nextValue = getAtomValue(nextVersion)
          if (Object.is(prev[1], nextValue) && prev[2] === atom) {
            return prev // bail out
          }
          return [nextVersion, nextValue, atom]
        },
        versionFromProvider,
        (initialVersion) => {
          const initialValue = getAtomValue(initialVersion)
          return [initialVersion, initialValue, atom]
        }
      )
  • 391쪽, 본문 밑에서 7번째 줄

    Zustand에서는 하나의 하나의 스토어를

    ==>

    Zustand에서는 하나의 스토어를

  • 412쪽, 본문 2번째 줄

    2번째 행은 13만 이라

    ==>

    2번째 행은 13만 이라

  • 534쪽, 본문 16번째 줄

    만약 이 옵션이 켜져 있다면 d.ts에 에러가 있다면 에러를 발생시킨다.

    ==>

    만약 이 옵션에 false를 주면 에러를 발생시킨다.

  • 660쪽, 예제 코드의 2번째 줄

    // legacy/createLegacyRoot를 promise로 layzy하게 불러온다.

    ==>

    // legacy/createLegacyRoot를 promise로 lazy하게 불러온다.
  • 698쪽, 본문 2번째 줄

    renderToPipeableStream 대신에 이 메서드를 사용해야 한다.

    ==>

    renderToNodeStream 대신에 이 메서드를 사용해야 한다.

  • 710쪽, 페이지 상단 예제 코드를 다음 코드로 교체

    function ProfilePage() {
      // initialResource는 Promise로 데이터를 불러오는 데 어느 정도 시간이 필요함
      const [resource, setResource] = useState(initialResource)
      return (
        <Suspense fallback={<h1>Loading posts...</h1>}>
          <Sibling name="two" />
          <ProfileTimeline resource={resource} />
        </Suspense>
      )
    }
  • 732쪽, 본문 3번째 줄

    서버에서 클라이언트에서 전송되는 결과물 또한

    ==>

    서버에서 클라이언트로 전송되는 결과물 또한

  • 809쪽, 본문 5번째 줄

    만약 사용자 뷰포트 너비에 맞춰 다른 이미지를 제공하고 경우,

    ==>

    만약 사용자 뷰포트 너비에 맞춰 다른 이미지를 제공하고 싶은 경우,

  • 822쪽, 본문 밑에서 3번째 줄

    페이지 내 콘텐츠가 표시되는 되는 시점

    ==>

    페이지 내 콘텐츠가 표시되는 시점

  • 843쪽, 본문 4~5번째 줄 삭제

    다음으로, 최초 뷰포트 영역에서 가장 눈에 띄는 부분 중 하나는 대문 사진인데, 이 영역은 리소스 중 65번째로 요청된다.

    ==>

    (삭제)

WHERE TO BUY · 정가 48,000원
WHERE TO BUY · 정가 48,000원