패스트캠퍼스 - 초격차 강의 :: Hook Flow

Edwin·2023년 3월 30일
0

조금조금 REACT

목록 보기
19/31
  • 본 포스트는 패스트캠퍼스 강의 중 일부를 요약정리한 내용입니다.

리액트에서의 랜더링 흐름 이해하기

먼저 위의 이미지에 대한 코드를 살펴보자.

<!DOCTYPE html>
<html lang="ko">
<body>
  <!-- HookFlow, 호출타이밍에 대해서 살펴보자.  -->
  <!-- 필요한 라이브러리 unpkg 으로 설치하기, CDN -->
  <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>


  <div id="root"><div> 
    <script type="text/babel">
      const root = document.getElementById('root')

      const Child = () => {
        console.log("       Child render Start")
        const [text, setText] = React.useState(()=> {
          console.log("       Child useState")
          return ""
        })
        const ChangeHandler = (e) => {
          setText(e.target.value)
        }
        React.useEffect(()=>{
          console.log("       - Child(useEffect) empty deps")
          return () => {
            console.log("       - Child(useEffect - Cleanup) empty deps")
          }
        },[])
        React.useEffect(()=>{
          console.log("       - Child(useEffect) no deps")
          return () => {
            console.log("       - Child(useEffect - Cleanup) no deps")
          }
        }) // 의존성배열이 없다면, 계속 렌더가 새로되면 그려진다.
        React.useEffect(()=>{
          console.log("       - Child(useEffect) text")
          return () => {
            console.log("       - Child(useEffect - Cleanup) text")
          }
        },[text])

        const element = (
          <>
          <input value={text} onChange={ChangeHandler} /> 
          <p>{text}</p>
          </>
        )
        console.log("       Child render end")
        return element
      }

      const App = () => {
        console.log("App reder start")
        const [showInput, setShowInput] = React.useState(()=> {
          console.log("App useState")
          return false
        })

        // 마지막에 있는 "App reder end" 다음에 실행됩니다. // 사이드이팩트이기에 렌더가 끝난 다음에 동작됩니다. 
        // 심지어 위에서 그린 Child 컴포넌트보다 후에 실행된다. 
        React.useEffect(()=>{
          console.log("- App(useEffect) empty deps")
          return () => {
            console.log("- App(useEffect - Cleanup) empty deps")
          }
        },[])
        React.useEffect(()=>{
          console.log("- App(useEffect) no deps")
          return () => {
            console.log("- App(useEffect - Cleanup) no deps")
          }
        }) // 의존성배열이 없다면, 계속 렌더가 새로되면 그려진다.
        React.useEffect(()=>{
          console.log("- App(useEffect) showInput")
          return () => {
            console.log("- App(useEffect - Cleanup) showInput")
          }
        },[showInput])

        const buttonhandler = () => {
          setShowInput(pre => !pre)
        }
        console.log("App reder end")
        return (
          <>
          <button onClick={buttonhandler} >serach</button>
          {showInput ? 
            <Child/>
            : null}
          
          </>
        )
      }
      
      ReactDOM.render(<App />, root) 
      
    </script>
</body>
</html>

먼저 위의 코드는 바벨을 이용하여, 리액트 앱 설치 없이 리액트의 JSX 문법으로 기록된 구문을 번역하여 HTML에 적용시킬 수 있는 것을 의미한다. 바벨을 사용하는 이유는 최근 JS 기능을 상용 브라우저에 호환되도록 하기 위함이다.

01 컴포넌트와 훅의 호출타이밍

01 해당 html이 실행되면, 최초로 렌더, 즉 화면에 그려지는 것은 노란색부분이다. 그리고 화면에는 버튼만 등장한다. 여기서 볼 수 있는 것은 만약 useEffect를 실행했다면, 해당 훅의 실행은 렌더가 발생되고 난 뒤에 실행된다는 점이다. 그리고 훅에 의존성 배열을 어떻게 설정했는지에 따라서 추후에 해당 기능이 동작되고 동작되지 않는 차별을 부여할 수 있다.

02 이후, 버튼을 클릭하면 상태가 변하면서 input 태그가 화면에 등장하게 되는데 그때의 부분이 콘솔의 녹색박스부분이다. input 태그는 부모컴포넌트에 주입한 자녀 컴포넌트(element)에 해당된다. 해당 컴포넌트는 부모컴포넌트가 화면에 그려지고 난 후에, 실행되며 그려진다. 그러나 여기서 볼 수 있듯이 부모태그에 있는 useEffect 의 실행은 달라지는데, 컴포넌트들이 전부 실행된 이후에 실행된다. 이때, 상태의 값이 변경되어 다시 렌더를 실행해주어야 하는 경우, 이전의 것들이 언마운트되고 다시 생성되는데, 순서가 인상깊다.

  • App useEffect 가 먼저 언마운트되고
  • 주입된 Child useEffect 가 마운트 된 이후에,
  • 최정적으로 App useEffect 가 다시 마운트 된다는 점이다.

03 이후, input 태그에 내용을 입력하면, 자녀컴포넌트의 상태만 변경되기 때문에, 부모태그의 렌더 없이 자녀 컴포넌트만 렌더되며 화면에 그려지는 것을 볼 수 있다. 이렇듯 전체가 렌더링 되는 것이 아니라, 이전 DOM과 이후 DOM에서 발생된 차이만 렌더되는 특징이 리액트가 채택한 VirtualDOM 방식의 렌더링이다.

04 이후, 버튼을 통해서 input을 제어하는 상태를 변경하면, child 컴포넌트가 언마운트되기 때문에, 콘솔에서 볼 수 있듯이, 사라지는 것을 볼 수 있고, 다시 화면에 App useEffect를 위해서 이전 것이 지워지고, 다시 그려지는 것을 확인해 볼 수 있다.

이것을 이해하는 것은, 렌더링의 선행과 후행되는 결과에 따라서 로직을 기록하기 위함이다. 이를 지혜롭게 사용함으로 원하는 시점에 렌더링을 제어해보자.

profile
신학전공자의 개발자 도전기!!

0개의 댓글