├── .DS_Store ├── .github ├── CODEOWNERS └── pull_request_template.md ├── .gitignore ├── README.md ├── 김석진 ├── 01_리액트 개발을 위해 꼭 알아야 할 자바스크립트.md ├── 03_리액트 훅 깊게 살펴보기.md ├── 04_서버 사이드 렌더링.md └── 05_리액트와 상태 관리 라이브러리 ├── 김지후 ├── 10장.리액트 17,18 변경사항 │ └── 정리.md ├── 11장.Next.js 13과 리액트 18 │ └── 정리.md ├── 12장.웹 지표 │ └── 정리.md ├── 14장.리액트와 웹페이지 보안 이슈 │ └── 정리.md ├── 1장.자바스크립트 │ ├── 1.자바스크립트의 동등 비교.md │ ├── 2.함수.md │ ├── 3.클래스.md │ ├── 4.클로저.md │ ├── 5.이벤트 루프와 비동기 통신의 이해.md │ ├── 6.리액트에서 자주 사용하는 자바스크립트 문법.md │ └── 7.선택이 아닌 필수, 타입스크립트.md ├── 2장.리액트 핵심요소 │ └── 정리.md ├── 3장.리액트 훅 │ └── 정리.md ├── 4장.Next.js │ └── 정리.md ├── 5장.상태관리 │ └── 정리.md ├── 6장.리액트 개발 도구 │ └── 정리.md ├── 7장.크롬 개발자 도구를 활용한 애플리케이션 분석 │ └── 정리.md └── 8장.리액트 코드 작성 환경 구축 │ ├── 1.eslint.md │ └── 2.react-testing.md ├── 박규성 ├── 1장 리액트 개발을 위해 꼭 알아야 할 자바스크립트.md ├── 2장 리액트 핵심 요소 깊게 살펴보기.md ├── 3장 리액트 훅 깊게 살펴보기.md ├── 4장 │ ├── 4장.md │ ├── image-1.png │ ├── image-2.png │ ├── image-3.png │ ├── image-4.png │ └── image.png ├── 5장.md └── README.md ├── 박수진 ├── 10_리액트 17과 18의 변경사항 살펴보기 │ └── README.md ├── 11_Next.js 13과 리액트 18 │ └── README.md ├── 12_모든 웹 개발자가 관심을 가져야 할 핵심 웹 지표 │ └── README.md ├── 13_웹페이지의 성능을 측정하는 다양한 방법 │ └── README.md ├── 14_웹사이트 보안을 위한 리액트와 웹 페이지 보안 이슈 │ └── README.md ├── 15_마치며 │ └── README.md ├── 1_리액트 개발을 위해 꼭 알아야 할 자바스크립트 │ ├── README.md │ └── image.png ├── 2_리액트 핵심 요소 깊게 살펴보기 │ ├── README.md │ ├── image-1.png │ └── image.png ├── 3_리액트 훅 깊게 살펴보기 │ └── README.md ├── 4_서버 사이드 랜더링 │ └── README.md ├── 5_리액트와 상태관리 라이브러리 │ └── README.md ├── 6_리액트 개발도구로 디버깅하기 │ ├── README.md │ ├── image-1.png │ └── image.png ├── 7_크롬 개발자 도구를 활용한 애플리케이션 분석 │ ├── README.md │ ├── image-1.png │ ├── image-2.png │ ├── image-3.png │ ├── image-4.png │ ├── image-5.png │ └── image.png ├── 8_좋은 리액트 코드 작성을 위한 환경 구축하기 │ └── README.md └── README.md ├── 유은지 ├── 1주차 │ └── README.md ├── 2주차 │ └── README.md ├── 3주차 │ └── README.md ├── 4주차 │ └── README.md └── 5주차 │ └── README.md ├── 조성원 ├── 01_리액트 개발을 위해 꼭 알아야 할 자바스크립트.md ├── 02_리액트 핵심 요소 깊게 살펴보기.md ├── 03_리액트 훅 깊게 살펴보기.md ├── 04_서버 사이드 렌더링.md ├── 05_리액트와 상태 관리 라이브러리.md ├── 06_리액트 개발 도구로 디버깅하기.md ├── 07_크롬 개발자 도구를 활용한 애플리케이션 분석.md ├── 08_좋은 리액트 코드 작성을 위한 환경 구축하기.md ├── 10_리액트 17과 18의 변경 사항 살펴보기.md └── images │ ├── 4-1.png │ ├── 4-2.png │ ├── 4-3.png │ ├── 6-1.png │ ├── 6-10.png │ ├── 6-11.png │ ├── 6-12.png │ ├── 6-2.png │ ├── 6-3.png │ ├── 6-4.png │ ├── 6-5.png │ ├── 6-6.png │ ├── 6-7.png │ ├── 6-8.png │ └── 6-9.png └── 하현준 ├── 01. 리액트 개발을 위해 꼭 알아야 할 자바스크립트 └── README.md ├── 02. 리액트 핵심 요소 깊게 살펴보기 └── README.md ├── 03. 리엑트 훅 깊게 살펴보기 └── README.md ├── 04. 서버 사이드 렌더링 └── README.md ├── 05. 리액트와 상태 관리 라이브러리 └── README.md ├── 06. 리액트 개발 도구로 디버깅하기 └── README.md ├── 07. 크롬 개발자 도구를 활용한 애플리케이션 분석 └── README.md ├── 08. 좋은 리액트 코드 작성을 위한 환경 구축하기 └── README.md ├── 10. 리액트 17과 18의 변경 사항 살펴보기 └── README.md ├── 11. Next.js 13과 리액트 18 └── README.md ├── 12. 모든 웹 개발자가 관심을 가져야 할 핵심 웹 지표 └── README.md ├── 13. 웹페이지 성능을 측정하는 다양한 방법 └── README.md ├── 14. 웹사이트 보안을 위한 리액트와 웹페이지 보안 이슈 └── README.md ├── 15. 마치며 └── README.md └── README.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Book-Study-For-Developer/Modern-React-Deep-Dive/9c07e7f9b521cb8c28517832270cd5bfe8bd696d/.DS_Store -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @haryan248 @jihoo-o @soojin-aqara @wontory -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | **Description** 2 | 3 | 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## ![image](https://github.com/Front-End-Book-Study/Modern-React-Deep-Dive/assets/51049245/15424391-49c1-4747-b72d-523cf27472bb) 2 | 3 | - ⏰ 스터디 일시: 매주 목요일 21시 30분(온라인)/오프라인은 되는 인원끼리 모여서 진행 4 | - 🏫 스터디 장소: 온/오프라인 병행 5 | - 📚 스터디 자료: 모던 리액트 딥다이브 (리액트의 핵심 개념과 동작원리부터 Next.js까지) 6 | - 예시 코드: https://github.com/wikibook/react-deep-dive-example 7 | - 정요표: https://wikibook.co.kr/react-deep-dive/ (초판이다보니 오탈자가 많은 것 같아요. [issue](https://github.com/wikibook/react-deep-dive-example/issues)도 같이 확인해주세요.) 8 | --- 9 | 10 | ### 🚀 진행 방식 11 | 12 | - 스터디 시간에는 정리한 내용을 짧게 발표하고, 질문을 바탕으로 토론해요. 13 | 14 | ### 📝 내용 정리 15 | 16 | - 매주 공부한 내용을 바탕으로 마크다운으로 정리해요. 17 | - 모든걸 적으려 하기보단, 중요하다고 생각하는 내용 위주로 적어요. 18 | - 마크다운 작성법은 [여기](https://gist.github.com/ihoneymon/652be052a0727ad59601)를 참고해주세요. 19 | 20 | ### 🙋‍♂️ 질문 21 | 22 | - 질문은 많이 준비하면 할수록 좋아요. 23 | - WHAT HOW WHY 방식으로 질문을 준비해요. 24 | - 퀴즈 형식으로 만들어도 좋고, 같이 토론할만한 질문이어도 좋아요. 25 | - 스터디 시간에 질문들을 랜덤으로 뽑아서 답변하고, 해당 답변을 바탕으로 토론 후 정리해요. 26 | 27 | #### 질문 예시 28 | 29 | - 컴포넌트와 훅의 차이가 무엇인가요? (WHAT) 30 | - 리액트에서는 왜 순수성을 지키는게 중요한가요? (WHY) 31 | - 어떻게 하면 자식 컴포넌트의 상태를 부모 컴포넌트에서 관리할 수 있을까요? (HOW) 32 | 33 | ### 📌 스터디 방법 34 | 35 | 1. 레파지토리를 `clone`해주세요. 36 | 2. `main` 브랜치에서 [아이디] 브랜치를 만들어주세요. ex) `haryan248` 37 | 3. `[아이디]` 브랜치에서 본인의 주차 폴더에 정리한 내용을 push 해주세요. ex) `하현준/1주차/README.md` 38 | 4. `[아이디]` 브랜치에서 `main` 브랜치로 `PR(Pull Request)`를 보내주세요. ex) `docs: 000 챕터 00내용 학습` 39 | 5. `PR`은 마지막에 확인한 사람이 머지를 진행해주세요. 40 | 41 | ### 🏃‍♂️ 스터디원 42 | 43 | 44 | 45 | 48 | 51 | 54 | 57 | 58 | 59 | 60 | 65 | 70 | 75 | 80 | 81 | 82 | 85 | 88 | 91 | 92 | 93 | 94 | 99 | 104 | 109 | 110 | 111 |
46 | 47 | 49 | 50 | 52 | 53 | 55 | 56 |
61 | 62 | 하현준 63 | 64 | 66 | 67 | 조성원 68 | 69 | 71 | 72 | 박규성 (중도 하차) 73 | 74 | 76 | 77 | 김지후 78 | 79 |
83 | 84 | 86 | 87 | 89 | 90 |
95 | 96 | 박수진 97 | 98 | 100 | 101 | 김석진 (중도 하차) 102 | 103 | 105 | 106 | 유은지 (중도 하차) 107 | 108 |
112 | -------------------------------------------------------------------------------- /김석진/01_리액트 개발을 위해 꼭 알아야 할 자바스크립트.md: -------------------------------------------------------------------------------- 1 | ## 원시 타입 2 | 3 | - **boolean** 4 | - 조건문에서 false라고 취급되는 값을 falsy, true라고 취급되는 값을 truthy라고 한다. 5 | - **null** 6 | - 명시적으로 비어 있음을 나타내는 값이다. 7 | - typeof로 null을 확인했을 때 해당 타입이 아닌 'object'가 반환된다. 8 | - **undefined** 9 | - 선언됐지만 할당되지 않은 값이다. 10 | - **number** 11 | - 각 진수별로 값을 표현해도 모두 10진수로 해석되어 동일한 값으로 표시된다. 12 | - **string** 13 | - 원시 타입이며 변경이 불가능하다. 14 | - 템플릿 리터럴을 사용하면 줄바꿈이 간으하고, 문자열 내부에 표현식을 사용 할 수 있다. 15 | - **symbol** 16 | - 중복되지 않는 어떠한 고유한 값을 나타내기 위해 만들어졌다. 17 | - 심벌을 생성하려면 반드시 `Symbol()`을 사용한다. 18 | - **bigint** 19 | - number가 다룰 수 있는 한계를 넘어서 더 큰 숫자를 저장 할 수 있게 해준다. 20 | - 끝에 n을 붙이거나, `BigInt` 함수를 사용하여 사용 할 수 있다. 21 | 22 | ## 객체 타입 23 | 24 | 배열, 함수, 정규식, 클래스 등.. 원시 타입 이외의 모든것, 자바스크립트를 이루고 있는 대부분의 타입이 객체 타입이다. 25 | 26 | ```tsx 27 | function hello1() {} 28 | function hello2() {} 29 | 30 | hello1 === hello2; // false 31 | // 객체는 육안으로는 같아 보여도 참조가 다르기 때문에 false가 반환된다. 32 | 33 | let hello = { 34 | hi: "hi", 35 | }; 36 | 37 | let hi = { 38 | hi: "hi", 39 | }; 40 | 41 | hello === hi; // false 42 | // 객체는 값을 저장하는게 아니라 참조를 저장하기 때문에 동일하게 선헌했던 객체라 하더라도 저장하는 순간 다른 참조를 바라보기 떄문에 false를 반환한다. 43 | ``` 44 | 45 | ## 자바스크립트의 또 다른 비교 공식, `Object.is` 46 | 47 | `Object.is`는 `==`과 `===`가 만족하지 못하는 몇 가지 특이한 케이스를 추가하기 위해 생겨난 ES6 최신 문법이다.
48 | 하지만 `Object.is`를 사용하더라도 객체 비교에는 `===`과 똑같이 작동한다. 49 | 50 | ```tsx 51 | Object.is({}, {}); // true 52 | 53 | Number.NaN === NaN; // false 54 | Object.is(Number.NaN, NaN); // true 55 | 56 | NaN === 0 / 0; // false 57 | Object.is(NaN, 0 / 0); // true 58 | ``` 59 | 60 | ## 리액트에서의 동등 비교 61 | 62 | 리액트에서는 `objectIs`를 기반으로 동등 비교를 하는 `shallowEqual`이라는 함수를 만들어 사용한다.
63 | `shallowEqual`은 얕은 비교까지만 구현하였는데 이유는 JSX props는 객체이고 props는 일차적으로만 비교하면 되기 때문이다. 64 | 65 | [shallowEqual 코드 바로가기](https://github.com/facebook/react/blob/8e2bde6f2751aa6335f3cef488c05c3ea08e074a/packages/shared/shallowEqual.js) 66 | 67 | ## 함수 표현식 68 | 69 | ```tsx 70 | const sum = function add(a, b) { 71 | return a + b; 72 | }; 73 | 74 | sum(10, 14); // 24 75 | add(10, 14); // 에러 76 | ``` 77 | 78 | ### 일급 객체란? 79 | 80 | 다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체를 의미한다. 81 | 82 | 자바스크립트에서 함수는 일급 객체다. 함수는 다른 함수의 매개변수가 될 수도 있고, 반환 값이 될 수도 있으며, 앞에서 본 것 처럼 할당도 가능하므로 일급 객체가 되기 위한 조건을 모두 갖추고 있다. 83 | 84 | add를 부르면 에러가 나는 것을 본다면 알 수 있듯이 함수 표현식에서 함수에 이름을 주는 것은 함수 호출에 도움이 안 되는, 코드를 읽는 데 방해가 될 수 있는 요소이다. 85 | 86 | ## 함수 표현식과 선언 식의 차이 87 | 88 | 함수 표현식과 선언 식의 가장 큰 차이는 호이스팅이다. 89 | 90 | ### 호이스팅이란? 91 | 92 | 함수 선언문이 마치 코드 맨 앞단에 작성된 것처럼 작동하는 자바스크립트의 특징을 의미한다. 93 | 94 | ```tsx 95 | hello() 96 | 97 | funtion hello() { 98 | console.log('hello') 99 | } 100 | 101 | hello() 102 | ``` 103 | 104 | 함수를 선언한 hello가 중간에 있음에도 불구하고, 맨 앞에서 호출한 `hello()`는 어떠한 에러도 없다.
105 | 이유는 함수의 호이스팅은 함수에 대한 선언을 실행 전에 미리 메모리에 등록하는 작업을 의미한다.
106 | 이러한 호이스팅의 특징 덕분에 함수 선언문이 미리 메모리에 등록됐고, 순서에 상관없이 정상적으로 호출할 수 있게 된 것이다. 107 | 108 | ## 화살표 함수 vs 일반 함수 109 | 110 | 화살표 함수에서는 constructor를 사용할 수 없다.
111 | 생성자로 화살표 함수를 사용하는 것은 불가능하다.
112 | 화살표 함수에서는 arguments가 존재하지 않는다. 113 | 114 | 화살표 함수와 일반 함수에 가장 큰 차이점은 this 바인딩이다.
115 | 화살표 함수는 함수 자체의 바인딩을 갖고 있지 않는다. 화살표 함수 내부에서 this를 참조하면 상위 스코프의 this를 그대로 따르게 된다. 116 | 117 | ## 즉시 실행 함수 118 | 119 | 함수를 정의하는 즉시 실행되는 함수이다. 120 | 121 | ```tsx 122 | (function () { 123 | return a + b; 124 | })(10, 24); 125 | 126 | (() => { 127 | return a + b; 128 | })(10, 24); 129 | ``` 130 | 131 | ## 고차 함수 132 | 133 | 자바스크립트가 일급 객체라는 특징을 활용한 함수이다.
134 | 함수를 인수로 받거나 결과로 새로운 함수를 반환시킬 수 있다. 135 | 136 | ```tsx 137 | const doubledArray = [1, 2, 3].map(() => item * 2); 138 | 139 | doubledArray; // [2, 4, 6] 140 | ``` 141 | 142 | ## 함수 부수 효과(side-effect)를 최대한 억제하라 143 | 144 | ### 가능한 한 함수를 작게 만들어라 145 | 146 | ### 누구나 이해할 수 있는 이름을 붙여라 147 | 148 | ```tsx 149 | useEffect(function apiRequest() { 150 | // .. do somthing 151 | }); 152 | ``` 153 | 154 | 위와 같이 useEffect 혹은 useCallback에 이름을 붙여준다면 개발자 경험이 향상될 수 있을 것이다. 155 | 156 | ## 클래스 157 | 158 | ```tsx 159 | const myCar = new Car("자동차"); 160 | 161 | Object.getPrototypeOf(myCar); 162 | // getPrototypeOf를 사용하면, 인수로 넘겨준 변수의 prototype을 확인할 수 있다. 163 | 164 | Object.getPrototypeOf(myCar) === Car.prototype; // true 165 | myCar.__proto__ === Car.prototype; // true 166 | // __proto__는 getPrototypeOf와 동일하게 작동하지만, 가급적이면 getPrototypeOf를 사용하면 좋다. 167 | ``` 168 | 169 | ## 클로저의 정의 170 | 171 | 클로저는 어휘적 환경을 조합해 코딩하는 기법이다. 172 | 173 | ### 어휘적 환경이란? 174 | 175 | 변수가 코드 내부에서 어디서 선언됐는지를 말하는 것이다. 176 | 177 | ## 변수의 유효 범위, 스코프 178 | 179 | 클로저를 이해하기 위해서는 변수의 유효 범위에 따라서 어휘적 환경이 결정된다.
180 | 이러한 유효 범위를 스코프라고 한다. 181 | 182 | ### 전역 스코프 183 | 184 | 전역 레벨에 선언하는 것을 전역 스코프라고 한다.
185 | 브라우저 환경에서 전역 객체는 Window, Node.js 환경에서는 global이 있다. 186 | 187 | ### 함수 스코프 188 | 189 | 자바스크립트는 기본적으로 함수 레벨 스코프를 따른다. 즉, {} 블록이 스코프 범위를 결정하지 않는다. 190 | 191 | ## 리액트에서의 클로저 192 | 193 | 클로저의 원리를 사용하고 있는 대표적인 것 중 하나가 바로 useState이다. 194 | 195 | ```tsx 196 | function Component() { 197 | const [state, setState] = useState(); 198 | 199 | function handleClick() { 200 | // useState 호출은 위에서 끝났지만, 201 | // setState는 계속 내부의 최신값(prev)을 알고 있다. 202 | // 이는 클로저를 활용했기 때문에 가능하다. 203 | setState((prev) => prev + 1); 204 | } 205 | } 206 | ``` 207 | 208 | ## 클로저를 사용 할 떄 주의 할 점 209 | 210 | - 클로저에 꼭 필요한 작업만 남겨두지 않는다면 메모리를 불필요하게 잡아먹는 결과를 이야기 할 수 있다. 211 | - 클로즈 사용을 적절한 스코프로 가둬두지 않는다면 성능에 악영향을 미친다. 212 | 213 | ## 이벤트 루프와 비동기 통신의 이해 214 | 215 | 자바스크립트는 싱글 스레드에서 작동한다. 즉, 기본적으로 자바스크립트는 한 번에 하나의 작업만 동기 방식으로만 처리할 수 있다. 216 | 217 | ### 동기란? 218 | 219 | 직렬 방식으로 작업을 처리하는 것을 의미하며, 이 요청이 시작된 이후에는 무조건 응답을 받은 이후에야 비로소 다른 작업을 처리 할 수 있다. 그동안 다른 모든 작업은 대기한다. 이러한 방식은 한번에 다양한 작업을 처리 할 수 없다. 220 | 221 | ### 비동기란? 222 | 223 | 직렬 방식이 아니라 병렬 방식으로 처리하는 것을 의미한다. 요청을 시작한 후 이 응당이 오건 말건 상관없이 다음 작업이 이루어지며, 따라서 한번에 여러 작업이 실행될 수 있다. 224 | 225 | ## 이벤트 루프란? 226 | 227 | 이벤트 루프란 자바스크립트 런타임 외부에서 자바스크립트의 비동기 실행을 돕기 위해 만들어진 장치라고 볼 수 있다. 228 | 229 | ### 호출 스택 230 | 231 | 호출 스택은 자바스크립트에서 수행해야 할 코드나 함수를 순차적으로 담아두는 스택이다.
232 | 코드를 실행하는 작업과 호출 스택이 비어있는지 확인하는 작업은 모두 단일 스레드에서 실행된다. 233 | 234 | ### 태스크 큐 235 | 236 | 태스크 큐란 실행해야 할 태스크의 집합을 의미한다.
237 | 이벤트 루프는 이러한 태스크 큐를 한 개 이상 가지고 있다.
238 | 큐의 형태가 아닌 set의 형태를 띠고 있다. 239 | 240 | ### 마이크로 태스크 큐 241 | 242 | 기존의 태스크 큐와는 다른 태스크를 처리한다.
243 | 마이크로 태스크 큐에는 대표적으로 Promise가 있다.
244 | 마이크로 태스크 큐는 태스크 큐보다 우선권을 갖는다. 245 | 246 | ## 리액트에서 자주 사용하는 자바스크립트 문법 247 | 248 | ### 객체 구조 분해 할당 249 | 250 | ### 전개 구문 251 | 252 | ### 객체 초기자 253 | 254 | ### map 255 | 256 | ### filter 257 | 258 | 기존 배열에 대해 어떠한 조건을 만족하는 새로운 배열을 반환할 때 쓰인다. 259 | 260 | ```tsx 261 | const arr = [1, 2, 3, 4, 5]; 262 | const evenArr = arr.filter((item) => item % 2 === 0); 263 | ``` 264 | 265 | ### reduce 266 | 267 | reducer 콜백 함수를 실행하고, 이를 초깃값을 추가로 인수를 받는데, 이 초깃값에 따라 배열이나 객체, 또는 그 외의 다른 무언가를 반환할 수 있는 메서스다. 268 | 269 | ```tsx 270 | const arr = [1, 2, 3, 4, 5]; 271 | const evenArr = arr.reduce((result, item) => { 272 | return result + item; 273 | }, 0); // result는 0 274 | // 15 275 | ``` 276 | 277 | ### forEach 278 | 279 | ### 삼항 조건 연산자 280 | 281 | ### JSX 내부에서 삼항 연산자 말고 다른 조건부 렌더링을 하는 법 282 | 283 | ```tsx 284 | export default function Component() { 285 | const [color, setColor] = useState(""); 286 | return ( 287 |
288 | {(() => { 289 | if (color === "red") { 290 | return "빨간색이다."; 291 | } else { 292 | return "빨간색이 아니다."; 293 | } 294 | })()} 295 |
296 | ); 297 | } 298 | ``` 299 | 300 | ## 타입스크립트란? 301 | 302 | 기존 자바스크립트 문법에 타입을 가미한 것이다.
303 | 자바스크립트는 동적 타입의 언어이기 떄문에 대부분의 에러를 코드를 실행했을 때만 확인할 수 있다는 문제점이 있다. 304 | 305 | ### any 대신 unknown을 사용하자 306 | 307 | any는 타입스크립트의 이점을 모두 버리는 것이나 다름없다.
308 | 309 | unknown으로 선언된 변수를 사용하기 우해서는 type narrowing, 즉 타입을 원래 의도했던 대로 적절히 좁혀야 한다. 310 | 311 | ```tsx 312 | function doSomething(callback: unknown) { 313 | if (typeof callback === "fucntion") { 314 | callback(); 315 | } 316 | 317 | throw new Error("callback은 함수여야 합니다."); 318 | } 319 | ``` 320 | 321 | ### 타입 가드를 적극 활용하자 322 | 323 | 타입을 사용하는 쪽에서는 최대한 타입을 좁히는 것이 좋다.
324 | 이러한 타입을 좁히는 데 도움을 주는 것이 바로 타입 가드다. 325 | 326 | ## 제네릭 327 | 328 | 제네릭은 함수나 클래스 내부에서 단일 타입이 아닌 다양한 타입에 대응할 수 있도록 도와주는 도구다. 329 | 330 | ```tsx 331 | function getFirstAndLast(list: T[]): [T, T] { 332 | return [list[0], list[list.length - 1]]; 333 | } 334 | ``` 335 | 336 | ### 인덱스 시그니처 337 | 338 | 인덱스 시그니처란 객체의 키를 정의하는 방식을 의미한다. 339 | 340 | ```tsx 341 | // 1 342 | type Hello = { 343 | [key: string]: string; 344 | }; 345 | 346 | const hello: Hello = { 347 | hello: "hello", 348 | hi: "hi", 349 | }; 350 | 351 | // 2 352 | type Hello = Record<"hello" | "hi", string>; 353 | 354 | const hello: Hello = { 355 | hello: "hello", 356 | hi: "hi", 357 | }; 358 | ``` 359 | 360 | ## 타입스크립트 전환 가이드 361 | 362 | ### tsconfig.json 먼저 작성하기 363 | 364 | ### JSDoc과 @ts-check를 활용해 점진적으로 전환하기 365 | 366 | 자바스크립트에서 타입스크립트로 전환하지 않고 타입을 체크하는 방법이 있다.
367 | 먼저 파일 최상단에 //@ts-check를 선언하고, JSDoc를 활용해 변수나 함수에 타입을 제공하면 타입스크립트 컴파일러가 자바스크립트 파일의 타입을 확인한다. 368 | 369 | ### 타입 기반 라이브러리 사용을 위해 @types 모듈 설치하기 370 | 371 | ### 파일 단위로 조금씩 전환하기 372 | -------------------------------------------------------------------------------- /김석진/03_리액트 훅 깊게 살펴보기.md: -------------------------------------------------------------------------------- 1 | ## useState 2 | - 함수형 컴포넌트 내부에서 상태를 정의하고, 이 상태를 관리할 수 있게 해주는 훅이다. 3 | 4 | ```tsx 5 | const [state, setState] = useState(initialState); 6 | ``` 7 | - useState의 인수로서 아무런 값을 넘겨주지 않으면 초깃값은 undefined이다. 8 | - 함수의 실행이 끝났음에도 함수가 선언된 환경을 기억할 수 있는 방법은 클로저 덕분이다. 클로저 내부에 useState와 관련된 정보를 저장해 두고, 필요할 떄마다 꺼내놓는 형식으로 구성돼 있다. 9 | 10 | ## 게으른 초기화 11 | - useState에 변수 대신 함수를 넘기는 것을 게으른 초기화(lazy initialization)라고 한다. 12 | - 인수에 함수를 넣으면 state가 처음 만들어질때만 실행되고 이후 리렌더링시에는 실행되지 않는다. 13 | - 게으른 초기화를 사용하여 무거운 연산이 요구되는 작업에 최적화 작업을 할 수 있다. 14 | 15 | ## useEffect 16 | - useEffect는 애플리케이션 내 컴포넌트의 여러 값들을 활용해 동기적으로 부수 효과를 만드는 함수이다. 17 | - useEffect는 생명주기 메서드를 대체하기 위해 만들어진 훅이 아니다. 18 | - useEffect에 첫번째 인수로는 부수 효과가 포함된 함수 두번째 인수에는 의존성 배열을 전달한다. 19 | - 함수형 컴포넌트는 매번 함수를 실행해 렌더링을 수행한다는 특징 덕분에 useEffect가 의존성 배열을 변경된 것을 알고 실행될 수 있는 것이다. 20 | 21 | ## 클린업 함수의 목적 22 | - 클린업 함수는 이벤트를 등록하고 지울 때 사용해야 한다고 알려져 있다. 23 | - 클린업 함수는 이전 state를 참조해 실행된다. 24 | - 클린업 함수는 함수형 컴포넌트가 리렌더링됐을 떄 의존성 변화가 있었을 당시 이전의 값을 기준으로 실행되는, 말 그대로 이전 상태를 청소해 주는 개념으로 보는 것이 좋다. 25 | 26 | ## 의존성 배열 27 | - 의존성 배열이 없는 useEffect는 매 렌더링마다 실행된다면 그냥 useEffect 없이 써도 되는거 아닌가? -> 두개는 명백한 차이점이 존재. 28 | 29 | - 서버 사이드 렌더링 관점에서 useEffect는 클라이언트 사이드에서 실행되는 것을 보장해 준다. useEffect 내부에서는 window 객체의 접근에 의존하는 코드를 사용해도 된다. 30 | - useEffect는 컴포넌트 렌더링의 부수 효과, 즉 컴포넌트의 렌더링이 완료된 이후에 실행된다. 반면 직접 실행은 컴포넌트가 렌더링되는 도중에 실행된다. 따라서 직접 실행은 서버 사이드 렌더링의 경우에 서버에서도 실행된다. 그리고 이 작업은 함수형 컴포넌트의 반환을 지연시키는 행위이기 때문에 무거운 작업일 경우 렌더링을 방해하므로 성능에 악영향을 미칠 수 있다. 31 | 32 | ## useEffect를 사용할 떄 주의할 점 33 | - eslint-disable-line react-hooks/exhaustive-deps 주석은 최대한 자제하라 34 | - useEffect의 첫 번째 인수에 함수명을 부여하라 35 | - 변수명을 통해 useEffect가 어떠한 역할을 하는지 파악 할 수 있다. 36 | - 거대한 useEffect를 만들지 마라 37 | - 만약 큰 useEffect를 만들어야한다면 분리해라 38 | - 의존성 배열이 너무 거대해진다면최대한 useCallback, useMemo 등으로 사전에 정제한 내용들만 useEffect에 담아두는 것이 좋다. 39 | - 불필요한 외부 함수를 만들지 마라 40 | 41 | ## useMemo 42 | - useMemo는 비용이 큰 연산에 대한 결과를 저장해 두고, 이 저장된 값을 반환하는 훅이다. 43 | 44 | ## useCallback 45 | - useCallback은 인수로 넘겨받은 콜백 자체를 기억하는 훅이다. 즉, 콜백 함수를 재생성하지 않고 재사용한다는 의미이다. 46 | - 첫 번째 인수로 함수를, 두 번째 인수로 의존성 배열을 집어 넣으면 useMemo와 마찬가지로 의존성 배열이 변경되지 않는 한 함수를 재생성하지 않는다. 47 | 48 | ## useMemo와 useCallback의 차이 49 | - useMemo와 useCallback의 차이는 메모이제이션을 하는 대상이 변수냐 함수냐 차이이다. 50 | 51 | ## useRef 52 | - useRef는 useState와 동일하게 컴포넌트 내부에서 렌더링이 일어나도 변경 가능한 상태값을 저장한다는 공통점이 있다. 53 | - useRef는 반환값인 객체 내부에 있는 current로 값에 접근 또는 변경할 수 있다. 54 | - useRef는 그 값이 변하더라도 렌더링이 발생시키지 않는다. 55 | - useRef는 컴포넌트가 렌더링될 떄만 생성되며, 컴포넌트 인스턴스가 여러 개라도 각각 별개의 값을 바라본다. 56 | 57 | ## useContext 58 | - props drilling을 극복하기 위해 등장한 개념이 Context이다. Context를 사용하면 이러한 명시적인 props 전달 없이도 선언한 하위 컴포넌트 모두에서 자유롭게 원하는 값을 사용할 수 있다. 59 | 60 | ## useContext를 사용할 때 주의할 점 61 | - useContext를 함수형 컴포넌트 내부에서 사용하면 재홞용이 어려워진다. 62 | - useContext가 선언돼 있으면 Provider에 의존성을 가지고 있는 셈잉 되므로 아무데서나 재활용하기에는 어려운 컴포넌트가 된다. 63 | - useContext는 부모 컴포넌트가 리렌더링되면 하위 컴포넌트도 전부 리렌더링된다. 64 | - 하위 컴포넌트가 리렌더링되지 않게 막으려면 React.memo를 써야한다. 65 | 66 | ## useContext는 상태 관리를 위한 API가 아닙니다 67 | - useContext는 상태를 주입해 주는 API다. 68 | 69 | 상태 관리 라이브러리가 디기 위서는 다음 두 가지 조건을 만족해야 한다. 70 | - 어떠한 상태를 기반으로 다른 상태를 만들어 낼 수 있어야 한다. 71 | - 필요에 따라 이러한 상태 변화를 최적화할 수 있어야 한다. 72 | 73 | ## useReducer 74 | - useReducer는 useState의 심화 버전으로 볼 수 있다. useState와 비슷한 형태를 띠지만 조금 더 복잡한 상태값을 미리 정의해 놓은 시나리오에 따라 관리할 수 있다. 75 | 76 | ## useImperativeHandle 77 | - useImperativeHandle은 부모에게서 넘겨받은 ref를 원하는 대로 수정할 수 있는 훅이다. 78 | 79 | [useImperativeHandle 리액트 공식 문서](https://react.dev/reference/react/useImperativeHandle) 80 | 81 | ## useLayoutEffect 82 | - useEffect와 동일하나, 모든 DOM의 변경 후에 동기적으로 발생하는 훅이다. 83 | - 동일하다는 것은 형태나 사용 예제가 동일하는 것을 의미한다. 84 | 85 | ### 실행 순서 86 | 1. 리액트가 DOM을 업데이트 87 | 2. useLayoutEffect를 실행 88 | 3. 브라우저에 변경 사항을 반영 89 | 4. useEffect를 실행 90 | 91 | [useLayoutEffect 블로그](https://junghyeonsu.com/posts/translation/useeffect-vs-uselayouteffect/) 92 | 93 | ## 훅의 규칙 94 | 95 | - 최상위에서만 훅을 호출해야 한다. 96 | - 반복문이나 조건문, 중첩된 함수 내에서 훅을 실행할 수 없다. 97 | - 이 규칙을 따라야만 컴포넌트가 렌더링될 때마다 항상 동일한 순서로 훅이 호출되는 것을 보장할 수 있다. 98 | - 훅을 호출할 수 있는 것은 리액트 함수 컴포넌트, 혹은 사용자 정의 훅의 두가지 경우 뿐이다. 99 | - 일반 자바스크립트 함수에서는 훅을 사용할 수 없다. 100 | - 이러한 규칙들은 react-hooks/rules-of-hook에 존재한다. 101 | 102 | ## 사용자 정의 훅과 고차 컴포넌트 중 무엇을 써야 할까? 103 | 104 | ### 사용자 정의 훅 105 | - 서로 다른 컴포넌트 내부에서 같은 로직을 공유하고자 할 때 주로 사용되는 것이 바로 사용자 정의 훅이다. 106 | - 복잡하고 반복되는 로직은 사용자 정의 훅으로 간단하게 만들 수 있다. 107 | 108 | ### 고차 컴포넌트 109 | - 고차 컴포넌트는 컴포넌트 자체의 로직을 재사용하기 위한 방법이다. 110 | - 리액트에서는 고차 컴포넌트 기법으로 다양한 최적화나 중복 로직 관리를 할 수 있다. 리액트에서 가장 유명한 고차 컴포넌트는 React.memo 111 | 112 | ### 고차 함수 만들어보기 113 | 114 | ```tsx 115 | function add(a) { 116 | return function (b) { 117 | return a + b 118 | } 119 | } 120 | 121 | const result = add(3) // 클로저에 기억 122 | const result2 = result(5) // 클로저에 기억된 정보를 가지고 더한 값이 출력됨 >> 8 123 | ``` -------------------------------------------------------------------------------- /김석진/04_서버 사이드 렌더링.md: -------------------------------------------------------------------------------- 1 | ## 서버 사이드 렌더링이란? 2 | 3 | **서버 사이드 렌더링(SSR)**은 웹 애플리케이션의 콘텐츠를 서버에서 렌더링하는 기술입니다. 4 | 5 | ## 싱글 페이지 애플리케이션이란? 6 | 7 | ### 과거의 도전과 SPA의 등장 8 | 9 | - 과거에는 자바스크립트로 수행할 수 있는 작업이 제한적이었기 때문에 대부분의 로직이 서버에서 처리되었습니다. 10 | - 이로 인해 애플리케이션 확장과 서버 유지보수가 어려워지는 문제가 발생했습니다. 11 | 12 | ### SPA의 등장 13 | 14 | - 자바스크립트의 진보와 REST API, AJAX의 등장으로 클라이언트 측에서 많은 작업을 수행할 수 있게 되었습니다. 15 | - 이로써 전체 페이지를 다시 요청하지 않고 클라이언트 측에서 라우팅하며 필요한 데이터만 서버에 요청하여 DOM을 업데이트하는 **싱글 페이지 애플리케이션(SPA)**가 등장했습니다. 16 | 17 | ## 다시 부각되는 서버 사이드 렌더링 18 | 19 | ### SSR의 장점 20 | 21 | - 초기 페이지 로딩이 빠릅니다. 22 | - SEO에 유리합니다. 23 | - 서버에서 렌더링을 수행하므로 디바이스 성능에 크게 의존하지 않습니다. 24 | 25 | ### SSR과 CSR 선택 시 고려사항 26 | 27 | - CSR을 적절히 활용하면 훌륭한 애플리케이션을 개발할 수 있습니다. 28 | - 일반적으로 CSR 애플리케이션은 SSR에 비해 성능이 떨어집니다. 29 | - CSR은 SEO에 취약합니다. 30 | - SSR은 서버 부하를 고려해야 합니다. 31 | 32 | ### 결론 33 | 34 | 따라서 어느 하나가 항상 우월한 것은 아니며, 상황에 따라 적절한 기술을 선택해야 합니다. 35 | 36 | ## 리액트에서 제공하는 SSR API 37 | 38 | ### renderToString 39 | 40 | - 주어진 리액트 컴포넌트를 HTML 문자열로 렌더링하는 함수입니다. 41 | - 리액트 훅과 이벤트 핸들러 등은 포함되지 않습니다. 42 | 43 | ```tsx 44 | import { renderToString } from 'react-dom/server'; 45 | 46 | const html = renderToString(); 47 | console.log(html); 48 | ``` 49 | 50 | [자세히 보기](https://react.dev/reference/react-dom/server/renderToString) 51 | 52 | ### renderToStaticMarkup 53 | 54 | - renderToString과 유사하지만 리액트 전용 속성을 생성하지 않고 순수한 HTML 문자열만 반환합니다. 55 | 56 | ```tsx 57 | import { renderToStaticMarkup } from 'react-dom/server'; 58 | 59 | const html = renderToStaticMarkup(); 60 | ``` 61 | 62 | [자세히 보기](https://react.dev/reference/react-dom/server/renderToStaticMarkup) 63 | 64 | ### renderToNodeStream 65 | 66 | - 결과물은 renderToString과 동일하지만 결과물의 타입이 Node.js의 ReadableStream으로 브라우저에서 사용할 수 없습니다. 67 | 68 | 69 | ```tsx 70 | import { renderToStaticNodeStream } from 'react-dom/server'; 71 | 72 | const stream = renderToStaticNodeStream(); 73 | stream.pipe(response); 74 | ``` 75 | 76 | [자세히 보기](https://react.dev/reference/react-dom/server/renderToStaticNodeStream) 77 | 78 | ### renderToStaticNodeStream 79 | - renderToStaticMarkup과 유사하지만 결과물의 타입이 ReadableStream입니다. 80 | 81 | 82 | ```tsx 83 | import { renderToStaticNodeStream } from 'react-dom/server'; 84 | 85 | const stream = renderToStaticNodeStream(); 86 | ``` 87 | 88 | [자세히 보기](https://react.dev/reference/react-dom/server/renderToStaticNodeStream) 89 | 90 | ### hydrate 91 | - renderToString 또는 renderToNodeStream으로 생성된 HTML에 자바스크립트 핸들러와 이벤트를 추가하는 메소드입니다 92 | - 서버에서 제공해 준 HTML과 클라이언트가 렌더링한 결과물이 같을 것으로 예상하고 동작합니다. 93 | - 결과물이 다를 경우 새로 hydrate가 렌더링한 기준으로 웹페이지를 그리게 됩니다. 94 | - 불가피하게 불일치가 발생할 경우 해당 요소에 suppressHydrationWarning을 추가해 경고를 끌 수 있습니다. 95 | 96 | ```tsx 97 | import { hydrate } from 'react-dom'; 98 | 99 | hydrate(reactNode, domNode); 100 | ``` 101 | 102 | [자세히 보기](https://react.dev/reference/react-dom/hydrate) 103 | 104 | ## NextJs 장점 105 | - 파일 기반 라우팅: App Router와 Page Router를 통해 자동으로 라우트를 생성합니다. 106 | - 자동 정적 최적화: SSR이 필요한지 자동으로 판단하고 필요하지 않은 페이지는 자동으로 SSG로 생성합니다. 107 | - API 라우트: 간단한 API 엔드포인트를 생성하여 백엔드 로직을 쉽게 통합할 수 있습니다. 108 | - 이미지 최적화: next/image를 통해 이미지를 자동으로 최적화하고 성능을 향상시킬 수 있습니다. 109 | - 코드 스플리팅: 필요에 따라 자동으로 코드 스플리팅을 수행하고 링크된 페이지를 110 | 프리페치할 수 있는 기능이 있습니다. -------------------------------------------------------------------------------- /김석진/05_리액트와 상태 관리 라이브러리: -------------------------------------------------------------------------------- 1 | # 상태와 상태 관리 2 | 3 | ## 상태의 필요성 4 | 5 | - 상태는 애플리케이션에서 지속적으로 변경될 수 있는 값을 나타낸다. 6 | - 웹 애플리케이션에서는 UI, URL, 폼, 서버에서 가져온 값 등 다양한 상태가 존재한다. 7 | 8 | ## 웹 애플리케이션에서의 상태 분류 9 | 10 | - **UI:** 다크/라이트 모드, 각종 Input 값, 알림창의 노출 여부 등 11 | - **URL:** 브라우저에서 관리되는 상태값으로 사용자의 라우팅에 따라 변경됨 12 | - **폼(form):** 로딩 여부, 제출 상태, 값의 유효성 등 13 | - **서버에서 가져온 값:** 서버로 요청을 통해 가져온 데이터 14 | 15 | # Flux 패턴의 등장 16 | 17 | - **MVC 패턴**은 모델과 뷰가 복잡해질수록 복잡성이 증가한다는 문제가 있었다. 모델과 뷰가 서로 간섭하고 양방향 통신을 하면서 코드의 유지보수가 어려워지는 문제가 발생했다. 18 | - 이를 해결하기 위해 **Flux 패턴** 두두등장! 19 | 20 | ## Flux 패턴의 도입 21 | 22 | - Flux 패턴은 단방향 데이터 흐름을 강조하여 데이터의 변화를 추적하기 쉽게 만들어졌다. 23 | - 이 패턴은 페이스북에서 개발한 패턴으로, 데이터의 흐름이 한 방향으로만 흐르도록 하는 아키텍처를 제공한다. 24 | 25 | ## Flux Architecture 26 | 27 | - **Action:** 애플리케이션에서 일어나는 어떤 작업을 나타내는 객체로, 액션 발생 시 함께 전달되는 데이터를 포함한다. 28 | 29 | - **Dispatcher:** 액션을 스토어로 전달하는 역할을 합니다. 액션이 정의한 타입과 데이터를 모두 스토어에 보낸다. 30 | 31 | - **Store:** 애플리케이션의 상태를 저장하고, 상태에 따라 값을 반환하거나 상태를 변경할 수 있는 메서드를 가지고 있다. 32 | 33 | - **View:** 사용자에게 보여지는 부분으로, 스토어에서 가져온 데이터를 이용하여 화면을 렌더링하고 사용자의 입력을 감지하여 액션을 발생시키기도 한다. 34 | 35 | Flux 패턴은 단방향 데이터 흐름으로 데이터를 추적하기 쉽게 만들어주며, 리액트와의 조합이 매우 자연스럽게 이루어지게 된다. 36 | 37 | # 상태 관리 라이브러리의 등장 38 | 39 | ## Redux 40 | 41 | - **Redux**는 하나의 상태 객체를 스토어에 저장하고, 디스패치를 통해 이 객체를 업데이트한다. 42 | - 전역 상태 객체를 사용하여 상태를 하위 컴포넌트에 전파할 수 있으며, 이는 props drilling을 해결하는 데 도움이 된다. 그러나 보일러플레이트의 양이 많아 사용이 번거롭다. 43 | 44 | ## Context API 45 | 46 | - **Context API**는 상태를 주입해주는 기능을 제공한다. 47 | - props를 넘기지 않아도 Context Provider가 주입하는 상태를 사용할 수 있다. 그러나 상태 관리가 아닌 주입을 도와주는 기능이며, 렌더링을 막아주는 기능은 없다. 48 | 49 | ## React Query와 SWR 50 | 51 | - **React Query**와 **SWR**은 외부에서 데이터를 불러오는 데 특화된 라이브러리로, HTTP 요청에 특화된 상태 관리를 제공한다. 52 | 53 | ## useState와 useReducer 54 | 55 | - **useState**의 등장으로 리액트에서는 간단하게 동일한 인터페이스의 상태를 생성하고 관리할 수 있다. 56 | - 하지만 지역 상태의 한계가 존재하며, 컴포넌트마다 초기화되어 컴포넌트별로 다른 상태를 가진다. 57 | 58 | # 상태 관리 라이브러리의 동작 방식 59 | 60 | - 상태 관리 라이브러리는 **useState**와 **useReducer**의 한계를 극복하기 위해 외부에 상태를 둔다. 61 | - 이 외부 상태 변경을 감지하고 컴포넌트의 렌더링을 일으켜 상태를 전파한다. 62 | 63 | # 상태 관리 라이브러리 살펴보기 64 | 65 | ## Recoil 66 | 67 | - **Recoil**은 최상단에 스토어를 만들고, **Atom**이라 불리는 최소 상태 단위를 등록하여 사용한다. 68 | - 컴포넌트는 Recoil에서 제공하는 훅을 통해 Atom의 상태를 구독하고, 값이 변경되면 리렌더링을 실행한다. 69 | - 비동기 작업을 쉽게 처리할 수 있는 API를 제공하며, 별도의 미들웨어 없이도 비동기 작업이 가능하다. 70 | 71 | ## Jotai 72 | 73 | - **Jotai**는 Recoil의 영감을 받아 만들어진 라이브러리로, 불필요한 리렌더링을 최소화하고 메모이제이션을 필요로 하지 않게 설계되었다. 74 | - 별 다른 세팅이 필요없고 사용하기 굉장히 쉽다는 장점이 있다. 75 | 76 | ## Zustand 77 | 78 | - **Zustand**는 하나의 중앙 스토어를 활용해 상태를 관리한다. 79 | - 코드 양이 적고 빠르게 스토어를 생성하고 사용할 수 있는 특징이 있다. 80 | - 리덕스와 함께 사용 가능한 여러 미들웨어를 지원하며, 상태를 간단하게 정의할 수 있어 가볍고 편리하다. 81 | -------------------------------------------------------------------------------- /김지후/10장.리액트 17,18 변경사항/정리.md: -------------------------------------------------------------------------------- 1 | # 리액트 17 버전 살펴보기 2 | 3 | ### 1. 리액트의 점진적인 업그레이드 4 | 5 | - React 16과 호환 가능 6 | - React 17 애플리케이션 내부에 React 16을 게으르게(lazy) 불러온다. 이 과정에서 React 16을 위한 별도의 루트 요소를 만들고, 여기에 불러온 React 16 모듈을 렌더링하는 구조 7 | 8 | ### 2. 이벤트 위임 방식의 변경 9 | 10 | - document -> 리액트 최상단 요소 11 | ![react_17_delegation](https://ko.legacy.reactjs.org/static/bb4b10114882a50090b8ff61b3c4d0fd/31868/react_17_delegation.png) 12 | - 각 이벤트는 해당 리액트 컴포넌트 트리 수준으로 격리되므로 이벤트 버블링으로 인한 혼선을 방지할 수 있다. 13 | - `stopPropagation`를 호출해도 같은 요소에 묶인 다른 이벤트 리스너들은 그대로 호출된다. 따라서 React 16에서 컴포넌트 루트가 아래처럼 나뉘었고, '특정 루트'에 대한 이벤트 전파를 막고 싶을지라도 모든 이벤트가 document에 등록되므로 불가능하다. 14 | ```html 15 |
16 |
17 |
18 |
19 | ``` 20 | 21 | ### 3. import React from 'react'가 더이상 필요 없다. 22 | 23 | - 기존에는 JSX 변환을 위해 `import React from 'react'`가 필요했으나 리액트 17부터는 필요없다. 24 | - React 17부터 바벨 변환시 React.createElement가 사라졌고, jsx 변환에 필요한 `react/jsx-runtime` 모듈을 내부적으로 호출한다. 25 | - `npx react-codemod update-react-imports`: 기존 소스코드의 `import React from 'react'` 삭제 26 | - 추후 쓰이지 않게 하려면 ESLint로 강제할 수도 있음 27 | - tsconfig.json의 jsx를 `react-jsx`로 변경하면 해당 방식으로 JSX 변환 28 | 29 | ### 4. 그 밖의 주요 변경 사항 30 | 31 | - 이벤트 풀링 제거 32 | - 이벤트 풀링은 이벤트가 발생할 때마다 새로운 이벤트 객체를 생성하는 대신, 이미 사용된 이벤트 객체를 '풀(pool)'에 저장하고 필요할 때 재사용하는 것을 의미. 이벤트 객체를 재사용하기 위해 사용된 개념 33 | - 해당 시스템에서는 이벤트 핸들러 함수가 호출되고 나면 해당 이벤트 객체의 모든 속성이 null로 설정되는데, 비동기적으로 이벤트 객체에 접근하려고 하면 문제가 발생해 `e.persist()` 같은 처리가 필요했음 34 | - useEffect 클린업 함수의 비동기 실행 35 | - 컴포넌트의 undefined 반환에 대한 일관적인 처리 36 | - 컴포넌트, forwardRef, memo에서 undefined 반환시 에러 37 | - React 18에서는 에러 발생 x 38 | 39 | # 리액트 18 버전 살펴보기 40 | 41 | ### 1. 새로 추가된 훅 살펴보기 42 | 43 | - `useId`: 고유한 키값 생성 44 | - 같은 컴포넌트여도 인스턴스 단위로 다른 값 생성 45 | - 클라이언트와 서버 불일치 해결 (Math.random의 hydration issue) 46 | - `useTransition`: UI의 변경을 가로막지 않고 상태를 업데이트 할 수 있는 함수 47 | - `동시성(concurrency)` 개념이 적용된 훅. 진행 중인 렌더링을 버리고 새로운 상태값으로 다시 렌더링 할 수 있음 48 | - state 업데이트 함수를 감싸서 사용 49 | - `useDeferredValue`: 디바운스와 유사 50 | - state 자체를 감싸서 사용 51 | - 상태를 업데이트할 수 있는 코드에 접근할 수 있다면 `useTransition`, props와 같이 값만 받아와야 하는 상황이라면 `useDeferredValue` 52 | - **`useSyncExternalStore`** -> 중요해 보이네요!! 53 | - 상태관리 라이브러리를 위한 훅 54 | - `동시성 이슈`, 하나의 state 값이 있음에도 서로 다른 값을 기준으로 렌더링되는 `tearing 현상`을 막기 위함 55 | - 리액트에서 관리할 수 없는 외부 데이터 소스에 대한 동시성 처리 추가 필요 56 | - `useSyncExternalStore(callbackToSubscribeExternalState, externalState, defaultValueForServerside)` 57 | - `useInsertionEffect` 58 | - `css-in-js` 라이브러리를 위한 훅 59 | - 실행 순서: 렌더링 -> `useInsersionEffect` -> 레이아웃 계산 -> `useLayoutEffect` -> 페인팅 -> `useEffect` 60 | 61 | ### 2. react-dom/client 62 | 63 | - `createRoot`: reat-dom의 render 메서드를 대체함 64 | - [소스코드](https://react.dev/blog/2022/03/08/react-18-upgrade-guide#updates-to-client-rendering-apis) 65 | - `hydrateRoot`: 서버사이드렌더링을 위한 `hydrate`에서 변경됨 66 | - [소스코드](https://react.dev/reference/react-dom/client/hydrateRoot#usage) 67 | 68 | ### 3. react-dom/server 69 | 70 | - `renderToPipeableStream` 71 | - `hydrateRoot`를 호출하면 서버에서는 HTML을 렌더링하고, 클라이언트의 리액트에서는 여기에 이벤트만 추가하여 첫 번째 로딩을 매우 빠르게 수행한다. 72 | - 이때 `renderToPipeableStream`을 쓰면 최초에 브라우저는 아직 불러오지 못한 데이터 부분을 `Suspense`의 fallback으로 받는다. 73 | - `renderToReadableStream` 74 | - `renderToPipeableStream`는 Node.js 환경, `renderToReadableStream`은 웹 스트림 기반으로 작동. 서버 환경이 아닌 클라우드플레어(Cloudflare)나 디노(Deno) 같은 웹 스트림을 사용하는 모던 엣지 런타임 환경에서 사용되는 메서드. 75 | 76 | ### 4. 자동 배치(Automatic Batchinig) 77 | 78 | - 여러 상태 업데이트를 하나의 리렌더링으로 묶어서 처리 79 | - 루트 컴포넌트를 `createRoot`로 생성하면 동기, 비동기, 이벤트 핸들러 등에 관계 없이 배치 수행됨 80 | - 배치를 피하고 싶은 경우 `flushSync` 사용 81 | 82 | ### 5. 더욱 엄격해진 엄격 모드 83 | 84 | - 더 이상 안전하지 않은 특정 생명주기를 사용하는 컴포넌트에 대한 경고 85 | - 더 이상 componentWillMount, componentWillReceiveProps, componentWillUpdate를 사용할 수 없음 86 | - 문자열 ref 사용 금지 87 | - 문자열이라 참조 파악이 어려운 것과 관련된 문제 발생 가능 88 | - findDOMNode에 대한 경고 출력 89 | - `findDOMNode`: 클래스형 컴포넌트 인스턴스에서 실제 DOM 요소에 대한 참조를 가져오는 데 사용 90 | - 클래스 내부에서 돔을 임의로 조작하면서 '컴포넌트의 렌더링을 위해서는 부모 컴포넌트의 렌더링이 이렁나야 한다'는 리액트의 추상화를 무너뜨림 91 | - 구 Context API 사용 시 발생하는 경고 92 | - childContextAPI, getChildContext 93 | - 예상치 못한 부작용(side-effects) 검사 94 | - strict mode에서 이중 호출되는 경우 95 | - 클래스형 컴포넌트의 constructor, render, shouldComponentUpate, getDerivedStateFromProps 96 | - 클래스형 컴포넌트의 setState의 첫 번째 인수 97 | - 함수형 컴포넌트의 body 98 | - useState, useMemo, useReducer에 전달되는 함수 99 | - console.log에 회색으로 출력됨 100 | - React 18에서 추가된 엄격 모드 101 | - 차후 마운트 해제된 상태에서도 상태값을 유지할 수 있는 기능이 제공될 예정이므로 이를 대비해 useEffect가 두번씩 실행된다. 102 | - 이를 고려해 적절한 cleanup 함수를 배치하는 것이 좋다. 103 | 104 | ### 6. Suspense 기능 강화 105 | 106 | - 수정된 버그 107 | - Suspense 내부에 출력된 컴포넌트가 실제로는 렌더링되지 않았음에도 effect 함수들이 실행되는 이슈 108 | - 서버에서 사용할 수 없는 문제 109 | - fallback 컴포넌트에 자동 스로틀링 지원 110 | - 한계 111 | - React.lazy를 쓰거나 Next.js와 같이 Suspense를 지원하는 프레임워크에서만 사용 가능 112 | - https://react.dev/reference/react/Suspense#usage 113 | 114 | ### 7. 인터넷 익스플로러 지원 중단에 따른 추가 폴리필 필요 115 | 116 | - Promise, Symbol, Object.assign 117 | -------------------------------------------------------------------------------- /김지후/12장.웹 지표/정리.md: -------------------------------------------------------------------------------- 1 | # 12.2 Core Web Vitals 2 | 3 | 구글에서 제안하는 핵심 웹 지표입니다. 4 | 5 | - 최대 콘텐츠풀 페인트(LCP, Largest Contentful Paint) 6 | - 최초 입력 지연(FID, First Input Delay) 7 | - 누적 레이아웃 이동(CLS, Cumulative Layout Shift) 8 | 9 | 추가로 최초 바이트까지의 시간(TTTB, Time To First Byte), 최초 콘텐츠풀 시간(FCP, First Contentful Paint)도 있습니다. 10 | 11 | # 12.3 최대 콘텐츠풀 페인트(LCP) 12 | 13 | ### LCP, 판단 기준 14 | 15 | LCP는 ‘페이지가 처음으로 로드를 시작한 시점부터 뷰포트 내에서 가장 큰 이미지 또는 텍스트를 렌더링하는 데 걸리는 시간’을 의미합니다. 큰 요소라고 하더라도 뷰포트를 넘어가면 제외됩니다. 16 | 17 | - 2.5초 이내: 좋음 18 | - 4초 이내: 보통 19 | - 그 이상: 나쁨 20 | 21 | 여기서 인식한다는 이미지와 텍스트는 다음과 같이 정의되어 있습니다. 22 | 23 | - 24 | - 내부의 25 | - poster 속성을 사용하는

,

) 28 | 29 | 34 | 35 | ### 개선 방안 36 | 37 | 이미지보다는 당연히 텍스트가 빠르게 로딩되고, 이미지의 경우 불러오는 방식에 따라 차이가 있습니다. 38 | 39 | 1. **img 태그** 40 | 2. svg 태그 41 | 3. **video 태그 + poster 속성** 42 | 4. background-image CSS 43 | 44 | 결과적으로 1, 3번이 가장 빠른데, 이는 브라우저의 프리로드 스캐너에 의해 발견되기 때문에 HTML 파싱 이전에 이미지를 미리 로딩할 수 있기 때문입니다. 45 | 46 | 그 밖에도 LCP 지표에 있어 주의해야 할 사항들이 존재합니다. 47 | 48 | - **이미지 무손실 압축**: 가능한 이미지를 **무손실 형식**으로 압축해 최소한의 용량으로 전달해야 합니다. 49 | - **loading=lazy**: loading=lazy는 해당 리소스의 중요도를 낮춰 필요할 때 로드하는 전략입니다. 해당 속성이 최대 콘텐츠풀 콘텐츠에 걸리면 로딩 속도를 늦춰 지표 점수에 도움이 되지 않습니다. 50 | - **fade in과 같은 애니메이션**: 애니메이션으로 인해 리소스가 늦게 출력된다면 이 역시 지표에 영향을 미칩니다. 51 | - **클라이언트 빌드**: 최적의 시나리오는 서버에서 빌드해온 HTML을 프리로드 스캐너가 읽어 콘텐츠풀 페인트로 빠르게 가져가는 것입니다. 52 | - **최대 콘텐츠풀 리소스는 직접 호스팅**: 외부 이미지를 가져오는 경우 네트워크 커넥션부터 다시 수행해야 하기 때문에 같은 도메인에서 직접 호스팅하는 것이 좋습니다. 53 | 54 | # 12.4 최초 입력 지연(FID) 55 | 56 | ### FID, 판단 기준 57 | 58 | FID는 웹사이트의 반응 속도와 관련된 지표입니다. 사용자의 최초의 입력 하나에 대한 응답 시간을 측정합니다. 59 | 60 | - 100ms 이내: 좋음 61 | - 300ms 이내: 보통 62 | - 그 이상: 나쁨 63 | 64 | 측정 대상은 클릭, 터치, 타이핑 등 입력 작업에 해당하며 스크롤이나 핀치 투 줌 등은 제외합니다. 65 | 66 | ### 개선 방안 67 | 68 | FID가 지연된다는 것은 브라우저의 메인 스레드가 오래 점유되고 있다는 것을 뜻합니다. 이 경우 아래의 두가지 방법으로 개선해 볼 수 있습니다. 69 | 70 | 1. 서버 처리 고려: 정말 클라이언트에서 처리해야 하는 경우가 아니라면 서버로 옮겨 브라우저의 메인 스레드를 오래 점유하지 않게 할 수 있습니다. 71 | 2. 긴 작업을 여러개로 분리: 여기서 ‘긴 작업’은 50ms 이상 걸리는 작업을 의미합니다. 이 경우 당장 노출될 필요가 없다면 리액트의 Suspense와 lazy, Next.js의 dynamic 등을 사용해 나중에 불러오도록 처리할 수도 있습니다. 72 | 3. 자바스크립트 코드 최소화: 사용하지 않는 코드는 최소화하는 것이 좋습니다. 이는 번들러가 해주는 작업이기도하지만 그 후에도 남아있으면서 실행된 적 없는 코드는 크롬 개발자 도구의 ‘커버리지’를 통해 확인할 수 있습니다. 이는 최초 실행시 필요하지 않다는 사실을 의미하므로 우선순위를 낮춰서 불러올 수 있습니다. 아울러 폴리필의 경우 브라우저 환경에 따라 구형 브라우저를 지원하지 않는다면 대부분의 폴리필을 사용할 필요가 없습니다. 많이 사용되지 않는 폴리필이라면 직접 자바스크립트 코드를 작성하는 것이 코드 크기를 줄일 수 있습니다. 73 | 4. 타사 자바스크립트 코드 실행 지연: Google Analytics나 firebase처럼 웹페이지 로드에 중요한 자원이 아니라면 async나 defer를 사용해 로딩을 지연시킬 수도 있습니다. async와 defer 모두 병렬로 다운로드 받는다는 공통점을 지니지만 async는 다운로드 즉시 실행되고, defer는 다운로드가 완료되어도 맨 마지막에 실행됩니다. 이때 광고의 경우라면 Intersection Observer를 이용해 해당 뷰포트에 진입했을 때 불러올 수도 있습니다. 74 | 75 | # 12.5 누적 레이아웃 이동(CLS) 76 | 77 | ### CLS, 판단 기준 78 | 79 | CLS는 누적 레이아웃 이동을 의미하며 예기치 않은 이동에 대한 지표를 계산합니다. 예를들어 렌더링 이후 useEffect를 통해 UI의 레이아웃이 변경되었다면 CLS 지표 점수가 올라갑니다. 이때 다른 요소의 시작 위치에 영향을 미치지 않았다면 계산되지 않습니다. 80 | 81 | - 영향분율: 레이아웃 이동이 발생한 요소의 전체 높이와 뷰포트 높이의 비율을 의미합니다. 82 | - 거리분율: 레이아웃 이동이 발생한 요소가 뷰포트 대비 얼마나 이동했는지를 의미합니다. 83 | - CLS = 영향분율 \* 거리분율 84 | 85 | 위의 수식을 보면 알 수 있듯이 뷰포트의 영향을 받기 때문에 기기마다 점수가 달라집니다. 86 | 87 | - 0.1 이하: 좋음 88 | - 0.25 이하: 보통 89 | - 그 이상: 나쁨 90 | 91 | ### 개선 방안 92 | 93 | 1. 삽입이 예상되는 요소를 위한 추가적인 공간 확보: useEffect는 useLayoutEffect로 대체할 수 있고, 스켈레톤 UI처럼 미리 레이아웃을 잡아둘 수도 있습니다. 혹은 서버 사이드 렌더링에서 HTML을 미리 제공하는 방법도 있습니다. 94 | 2. 폰트 로딩 최적화: 폰트가 변경되거나 폰트 변경으로 인해 텍스트가 출력되지 않는 경우 누적 레이아웃 이동이 발생할 수 있습니다. 이 경우 폰트를 불러오는 태그에 preload를 사용해 폰트를 미리 불러와 UI 방해를 줄일 수 있습니다. 또는 font-family에 auto, block, swap, fallback, optional 등의 옵션을 조합해 다운로드 우선순위를 조정하고 이에 실패했다면 적절한 fallback을 구성할 수 있습니다. 95 | 3. 적절한 이미지 크기 설정: 이미지 비율을 유지하기 위해 가장 많이 쓰이는 css, `width: 100%, height: auto`는 이미지 사이즈가 뒤늦게 조정되면서 누적 레이아웃 이동을 발생시킵니다. 이는 이미지 사이즈를 구체적으로 작성하되 비율을 맞춰 지정하면 `aspect-ratio` 속성 덕분에 로딩 이전에 사이즈를 맞춰 출력하게 됩니다. 만약 뷰포트 너비에 맞게 이미지 사이즈를 다르게 조절하고 싶다면 `srcset` 속성을 사용할 수 있습니다. 96 | 97 | # 그 외의 지표들 98 | 99 | - TTFB: 최초 응답이 오는 바이트까지가 얼마나 걸리느지를 측정하는 지표입니다. 100 | - FCP: 페이지가 로드되기 시작한 시점부터 페이지 콘텐츠의 일부가 화면에 렌더링될 때까지의 시간을 측정합니다. 이때 일부에 포함되는 요소는 텍스트, 이미지, svg 등을 의미합니다. 101 | -------------------------------------------------------------------------------- /김지후/14장.리액트와 웹페이지 보안 이슈/정리.md: -------------------------------------------------------------------------------- 1 | # 1. 리액트에서 발생하는 크로스 사이트 스크립팅(XSS) 2 | 3 | ### 1. dangerouslySetInnerHTML prop 4 | 5 | - JSX는 기본적으로 이스케이프 작업을 수행하지만, dangerouslySetInnerHTML는 별도의 검증이 필요하다. 6 | 7 | ### 2. useRef를 활용한 직접 삽입 8 | 9 | - `ref.current.innerHTML = html`처럼 html을 직접 조작하는 경우 보안 취약점이 있는 스크립트가 삽입될 우려가 있다. 10 | 11 | ### 3. 리액트에서 XSS 문제를 피하는 방법 12 | 13 | - 제3자가 삽입할 수 있는 HTML을 안전한 HTML 코드로 치환하는 것이다. 14 | - 새니타이즈(sanitize) 또는 이스케이프(escape)라고 한다. 15 | - 이러한 과정은 서버에서 처리하는 것이 좋다. 모든 데이터가 프론트를 거쳐서 들어오는 것은 아니기 때문이다. 16 | - 관련 라이브러리는 다음과 같다. 17 | - DOMpurity 18 | - sanitize-html 19 | - js-xss 20 | 21 | # 2. getServerSideProps와 서버 컴포넌트의 주의사항 22 | 23 | - getServerSideProps가 반환하는 모든 prop은 외부에 노출된다. 24 | - 뿐만 아니라 서버 컴포넌트가 클라이언트 컴포넌트에 반환하는 값도 주의해야 한다. 25 | 26 | # 3. 태그 값의 제한 27 | 28 | - 사용자가 입력한 주소로 이동하는 경우 새니타이즈 과정이 필요하다. 29 | - 피싱 사이트로 이동하는 것을 막기 위해 origin도 확인해 처리하는 것이 좋다? 30 | 31 | # 4. HTTP 보안 헤더 32 | 33 | ### 1. Strict-Transport-Security 34 | 35 | - http로 요청해도 https로 이동 36 | 37 | ### 2. X-XSS-Protection 38 | 39 | - 비표준 기술 40 | - XSS 취약점이 발견되면 페이지 로딩을 중단 41 | 42 | ### 3. X-Frame-Options 43 | 44 | - frame, iframe, embed, object 내부에서 렌더링을 허용할지 결정 45 | - 제3의 페이지에서