React의 작동 원리 3 - 최종 승인자 REACT-DOM

김명성·2022년 5월 13일
0

REACT

목록 보기
28/32
// 리액트가 컴포넌트를 재평가할때, 전체 함수를 재실행하고 , 이를 통해 코드 전체를 re-build한다.
// 코드 전체를 리빌드한다는 뜻은 jsx 코드가 최신 snapshot의 출력 결과를 re-build한다는 것이다.
// re-build 후 jsx 코드 내에 있는 모든 컴포넌트를 재실행한다.
// 그렇기 때문에, React.memo와 useCallback을 통해 함수나 변경되지 않은 값의 재실행을 막는 것이다.

function App() {


  const [showParagraph, setShowParagraph] = useState(false);
  const [allowToggle, setAllowToggle] = useState(false);


  console.log('App Running');

// useCallback hook은 기본적으로 컴포넌트 실행 전반에 걸쳐 함수를 저장할 수 있게 하는 훅이다.
// React에게 이 함수를 저장할 것이고, 매번 실행때마다 이 함수를 재생성할 필요가 없다는 걸 useCallback을 통해 알릴 수 있다.
// useCAllback을 통해 알리게 되면, 동일한 함수 객체가 메모리의 동일한 위치에 저장되므로 이를 통해 비교 작업을 할 수 있게된다.
// 객체가 같은 메모리 안의 같은 위치를 가리키고 있다면 이 두 객체는 같은 객체로 간주하게 되는데,
// 이 것이 useCallback이 하는 일로, 선택한 함수를 리액트의 내부 저장 공간에 저장하여
// 함수 객체가 실행될 때마다 이를 재사용할 수 있게 만든다.
// useCallback의 첫번쨰 인자로 함수를 전달하면, 재실행 될 때마다 React가 저장된 함수를 찾아 재사용한다.
// useCallback의 두번째 인자는 의존성 배열로 useEffect의 의존성 배열과 같은 기능을 한다.
// 의존성 배열에 state,props,context를 지정하여 변화를 감지할 수 있게 만든다.
// 처음에는, 의존성 배열이 왜 필요한지 의아해 할 수 있다.
// 함수는 불변하고, 항상 똑같은 로직을 쓰는데 왜 필요할까?
// 이 부분을 이해하기 위해서는 자바스크립트의 클로저라는 개념을 이해해야 한다.
// 
  const toggleParagraphHandler = useCallback(() => {
    // allowToggle이 활성화 될 경우에 토글될 수 있게 한다.
    // 하지만 아무 일도 일어나지 않을 것이다.
    // 그 이유는 자바스크립트에서 함수는 클로저이고, 이 경우에는 useCallback을 제대로 사용하지 않기 때문이다.
    // useCallback의 첫번째 인수로 담긴 함수는 현재 클로저로 움직이고 있다.
    // App 함수 내부에 있는 변수를 useCallback에 담긴 함수가 사용하고 있는 것이다.
    // 따라서 자바스크립트는 이 변수에 클로저를 만들고, 함수를 정의할 때 사용하기 위해 상수를 저장한다.
    // 다음 toggleParagraphHandler가 실행이 되면 이 저장된 변수를 그대로 사용하게 된다.


    if(allowToggle){
      setShowParagraph(prev => !prev);
    }
    // useCallback을 통해 어떤 환경에서든지 함수의 재생성을 막은 뒤로
    // toggleParapraphHandler에 담긴 allowToggle은 항상 false값이다.
    // 함수 생성 시점의 allowToggle 값을 저장하고 있기 때문이다.
    // 그렇기 때문에, allowToggle을 종속 형태로 추가해야한다.
  },[allowToggle]);

  //해당 함수는 토글 값을 토글하지 않고, 다른 버튼에 대한 토글을 활성화한다.

  const allowToggleHandler = () => {
    setAllowToggle(true)
  }



  //리액트에서는 주로 함수형 컴포넌트와 함께한다.
// 어쨋든, 컴포넌트는 결국 하나의 작업을 수행하는데, return문에 적힌 JSX코드이다.
// 컴포넌트에서 state, props, context를 이용해 작업할 수 있고,
// props와 context는 state의 변경으로 이어지기 때문에
// props,context,state의 변경은 컴포넌트가 재실행되고 재평가 된다는 의미이다.
// 따라서 모든 코드가 재실행되면 새로운 출력값을 얻을 수 있다.
// 출력값은 동일해 보이지만, 실제로는 조금 다르다.
// 예를 들어서 DemoOutput 내에 있는 text가 렌더링 되지 않을 수도 있다.
// React는 단순히 최신 평가의 결과를 가지고 직전 평가의 결과와 비교하고
// 확인된 모든 변경 사항이나 차이점을 REACT-DOM에 전달한다.
// 그리고 REACT-DOM을 통해 index.js 파일을 렌더링한다.
  return (

    

    <div className="app">
      <h1>Hi there!</h1>
      <DemoOutput show={showParagraph}/>
      <Button onClick={allowToggleHandler}>Allowed Toggling</Button>
      <Button onClick={toggleParagraphHandler}>Toggle Paragraph</Button>
      
    </div>
  );
}

export default App;

REACT-DOM은 index.js에서 확인할 수 있다.

// index.js

// React는 단순히 최신 평가의 결과를 가지고 직전 평가의 결과와 비교하고
// 확인된 모든 변경 사항이나 차이점을 REACT-DOM에 전달한다.
// 그리고 REACT-DOM을 통해 index.js 파일을 렌더링한다.
ReactDOM.render(<App />, document.getElementById('root'));

0개의 댓글