diff --git "a/04\355\232\214/sojeong/4-1.md" "b/04\355\232\214/sojeong/4-1.md" new file mode 100644 index 0000000..ddbd7a8 --- /dev/null +++ "b/04\355\232\214/sojeong/4-1.md" @@ -0,0 +1,56 @@ +# 4회차 - 1. 렌더링하고 커밋하기 + +# 렌더링이란? + +> **“Rendering” is React calling your components.** +> + +흔히 “렌더링”을 실제로 react가 화면에 컴포넌트를 그리는 것이라고 생각 하기 쉽다. +하지만 렌더링은 컴포넌트가 브라우저에 표시 되는 과정이 아니라 컴포넌트를 **호출**하여 화면에 표시할 내용을 파악하는 과정이다. 즉 **렌더링**은 **리액트**가 **컴포넌트**를 **호출** 하는 것이다. + +*참고: 리액트에서 컴포넌트의 렌더링은 재귀적으로 일어난다. 컴포넌트가 중첩되어 있다면 더 이상 nested 된게 없을 때까지 렌더링이 계속된다. 이 때문에 부모 컴포넌트의 렌더링이 자식 컴포넌트의 렌더링까지 촉발 하게 되는 것. + +# UI가 렌더링 되는 과정 + + + +> 순서 +> +> 1. **Triggering** a render (delivering the guest’s order to the kitchen) +> 2. **Rendering** the component (preparing the order in the kitchen) +> 3. **Committing** to the DOM (placing the order on the table) + +렌더링 조건에 따라 렌더링이 trigging 되고 → 리액트는 컴포넌트를 호출해서 표시할 내용 및 변경 사항(재렌더링일 시)을 파악 후 → DOM을 실제로 조작한다. + + + +# 언제 리액트는 컴포넌트를 렌더링 하나? + +> 두가지 이유 +> +> 1. It’s the component’s **initial render.** +> 2. The component’s (or one of its ancestors’) **state has been updated.** + +리액트는 두가지 경우에 컴포넌트를 렌더링한다. +하나는 첫 렌더링인 경우.(which is obvious :p) 그리고 조상(상위 요소)중 하나의 state가 변경된 경우. +root.render() 메소드로 DOM 루트에 진입 후 첫 렌더링이 일어나게 되고 이후에는 state가 변경 되는 경우 재렌더링이 일어난다. + +# DOM 수정 (변경사항 커밋) + +> 초기 렌더링인 경우와 리렌더링인 경우 +> +> - **For the initial render,** React will use the `[appendChild()](https://developer.mozilla.org/docs/Web/API/Node/appendChild)` DOM API to put all the DOM nodes it has created on screen. +> - **For re-renders,** React will apply the minimal necessary operations (calculated while rendering!) to make the DOM match the latest rendering output. + +초기 렌더링에서는 DOM 트리가 새로 만들어지게 되고, 리렌더링의 경우에 리액트는 이전과 비교 했을 때 달라진 부분만 DOM을 변경한다. 여기서 Virtual DOM의 장점이 나오게 되는 것이다. 수많은 DOM 조작이 일어나지만 모든 연산이 끝난 후의 결과로 실제의 DOM 계산을 딱 한번 수행 하고 이 과정을 라이브러리를 사용하는 사람은 알 필요 없게 해주는 것. React를 쓰는 이유라고 할 수 있다. \ No newline at end of file diff --git "a/04\355\232\214/sojeong/4-2.md" "b/04\355\232\214/sojeong/4-2.md" new file mode 100644 index 0000000..18a2fa3 --- /dev/null +++ "b/04\355\232\214/sojeong/4-2.md" @@ -0,0 +1,27 @@ +# 4회차 - 2. 스냅샷으로서의 state ~ 내용 전체 + +# state는 특별한 기능이 있는 변수일까? + +그래서 react가 이를 감지하고 재렌더링을 하는걸까? setState로 state를 변경하면 그 변경은 언제 일어나게 될까? react의 useState는 어떻게 각자의 state가 대응하는 setter를 사용할지를 알까? 이번 장에서는 이런 의문들에 대해 답을 해보도록 하자. + +# setState를 하면 일어나는 일 + +> You might think of your user interface as changing directly in response to the user event like a click. In React, it works a little differently from this mental model. On the previous page, you saw that [setting state requests a re-render](https://react-ko.dev/learn/render-and-commit#step-1-trigger-a-render) from React. This means that for an interface to react to the event, you need to *update the state*. +> + +useState의 반환값으로 받아온 setState를 사용하여 state를 변경하면 그 즉시 값이 변경 되는 것으로 오해할 수 있다. 하지만 react의 멘탈 모델은 그것과는 조금 다르다. setState가 호출 되었을때 리액트는 리렌더링을 “요청” 한다. 그러면 그 값을 큐에 담아두었다가, 다음 렌더링 때 새로운 값에 따라 컴포넌트를 리렌더링 하게 되는 것이다. + +# **Rendering takes a snapshot in time** + +> [“Rendering”](https://react-ko.dev/learn/render-and-commit#step-2-react-renders-your-components) means that React is calling your component, which is a function. The JSX you return from that function is like a snapshot of the UI in time. Its props, event handlers, and local variables were all calculated **using its state at the time of the render.** +> + +이게 무슨 말일까? 스냅샷을 찍는다? +사실 렌더링이 일어날 때 컴포넌트 내부의 state는 절대 변하지 않는다. state는 렌더링이 일어나는 시점의 그 state 값으로 “고정”되어있다. 이건 사실 꽤나 중요한 멘탈모델이자 패러다임이다. 이렇게 동작 하기 때문에 우리는 React Hook이라는 것을 쓸 수 있는 것이고, 함수형 컴포넌트와 클래스형 컴포넌트의 차이도 생긴다. +이에 대한 insight를 얻었던 글과 유용하게 읽었던 글을 첨부하겠다. 나머지 모든 챕터의 내용이 링크의 글들을 참고하면 이해 될 것이다! + +[useEffect 완벽 가이드](https://overreacted.io/ko/a-complete-guide-to-useeffect/) + +[함수형 컴포넌트와 클래스, 어떤 차이가 존재할까?](https://overreacted.io/ko/how-are-function-components-different-from-classes/) + +[React hooks: not magic, just arrays](https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e) \ No newline at end of file diff --git "a/10\355\232\214/\355\225\234\354\206\214\354\240\225/10.md" "b/10\355\232\214/\355\225\234\354\206\214\354\240\225/10.md" new file mode 100644 index 0000000..e1f7c35 --- /dev/null +++ "b/10\355\232\214/\355\225\234\354\206\214\354\240\225/10.md" @@ -0,0 +1,260 @@ +# Effect 의존성 제거하기 + +## useEffect 의존성 배열에 빈 배열을 써도 될까? + +혹시 생각 해본적 있는가? 린터 오류를 무시하기 위해 이유를 모른채 빈배열을 일단 써오지는 않았는가? 오늘은 이 주제에 대해서 얘기해보려 한다. + +## 의존성 배열이란? + +> When you write an Effect, the linter will verify that you’ve included every reactive value (like props and state) that the Effect reads in the list of your Effect’s dependencies. This ensures that your Effect remains synchronized with the latest props and state of your component. Unnecessary dependencies may cause your Effect to run too often, or even create an infinite loop. Follow this guide to review and remove unnecessary dependencies from your Effects. + +Effect가 실행될 때 react는 useEffect의 두번째 인자로 들어가는 배열에 들어가있는 값이 바뀌었는지를 확인하고 바뀌었다면 재실행한다. 이 배열을 의존성 배열이라고 하는데 linter가 Effect가 사용하는 모든 props, state와 같은 반응형 값을 포함하고 있는지를 확인한다고 설명이 써있다. +그래서 빈 배열을 주면 + +``` +Lint Error +11:6 - React Hook useEffect has a missing dependency: 'roomId'. Either include it or remove the dependency array. +``` + +라는 오류가 발생하게된다. + +그럼 왜 빈배열을 주면 오류를 발생시키게 만들어놨을까? + +## 의존성에게 거짓말을 하지 마라 + +``` +useEffect(() => { + document.title = 'Hello, ' + name; +}, [name]); +``` + +위의 코드에서 의존성 배열은 이펙트 내에서 쓰이는 모든 값을 가지고있다. 이로써 이펙트는 언제 다시 이펙트를 실행해야 할지 알고있다. 가령 name이 dan에서 yuji로 바뀌게 되면 의존성이 다르기때문에 이펙트를 재실행한다. +하지만 저 배열에 []를 줬다면, 이펙트는 두번 다시 새로 실행 되지 않는다. + +이런 경우는 어떨까? 매 초마다 숫자가 올라가는 카운터를 작성하고싶다. 그러면 이런 생각을 할 수 있다. "이펙트를 한 번만 설정하고, 한 번만 제거하자." 그럼 이런 코드가 나온다. + +``` +function Counter() { + const [count, setCount] = useState(0); + + useEffect(() => { + const id = setInterval(() => { + setCount(count + 1); + }, 1000); + return () => clearInterval(id); + }, []); + return