React 10일차

지나가는 행인·2024년 2월 1일

React

목록 보기
10/11

전에 배운 것과 오늘 배운 것이 섞여 있습니다.

컴포넌트 순수하게 유지

순수 함수의 조건

  • 주어진 처리만 진행
  • 동일 입력, 동일 출력
  • 함수 범위 밖의 변수나 호출 전에 생성된 객체를 변경 X
    하지만, 렌더링 되는 동안 방금 만든 변수와 객체를 변경 O


사이드 이펙트

렌더링 하는 동안이 아닌 외부에서 발생하는 부수적인 일들
ex) 화면 업데이트, 애니메이션, 데이터 변경

사이드 이펙트 처리

  • 일반적으로 이벤트 핸들러에 연결

  • 이벤트 핸들러는 컴포넌트 내부에 정의되어 있지만, 렌더링 중에 실행 X
    즉, 이벤트 핸들러는 순수할 필요 없음

  • 이벤트 핸들러가 없는 경우
    컴포넌트 내부에 useEffect hook을 호출해 컴포넌트가 반환한 JSX에 연결 가능
    하지만, 이런 방법은 꼭 필요한 경우(DOM 접근 조작 등)에만 사용하자


StrictMode로 사이드 이펙트 감지

  • 렌더링 하는 동안 3가지 유형의 입력을 읽을 수 있음(props, state, context)
  • 컴포넌트의 기능을 2번 호출하여 순수 함수 규칙을 위반하는 컴포넌트를 찾는 데 도움을 줌
  • 순수함을 유지한다면 2번 호출해도 정상 작동, 배포에 영향 X


로컬 뮤테이션(mutation)

  • 기존 값을 변경하는 것을 뮤테이션이라 함
  • 컴포넌트가 렌더링 되는 동안 기존 변수를 변경하면 안됨
  • 내부적으로만 수정하게 되면 컴포넌트 외부에서는 어떤 일이 발생했음을 알 수 없음
    컴포넌트 내부적으로만 생성, 수정이 이뤄지는 것을 로컬 뮤테이션


리액트가 순수함을 중요하게 생각하는 이유?

  • 컴포넌트가 다른 환경(ex. 서버)에서 실행될 수 있기 때문 (동일 입력, 동일 출력)
  • 입력이 변경되지 않은 렌더링은 건너 뛰기 때문에 성능 향상
  • 컴포넌트가 깊은 트리를 렌더링하고 있어도 일부 데이터가 변경되면 오래된 렌더링은 버리고
    다시 시작할 수 있음


상태

일반 JS에서 처럼 사용하면 화면이 변경되지 않는 이유

  • 함수내 지역 변수는 렌더링 간에 값을 기억 X
    : 컴포넌트를 다시 렌더링 할 때 함수 영역은 다시 초기화됨 (변수도 초기화)

  • 지역 변수를 변경해도 렌더링 X
    : 리액트는 지역 변수 값이 변경돼도 컴포넌트를 다시 렌더링 해야 한다고 인식 안함

새 데이터로 컴포넌트를 업데이트 하려면 필요한 조건

  1. 렌더링 간 데이터를 기억할 수 있어야 함
  2. 리액트가 새로운 데이터로 컴포넌트를 다시 렌더링 하도록 해야 함

useState hook이 위에서 필요로 하는 조건을 제공해준다.

  1. 렌더링 간 데이터를 기억할 수 있는 상태 변수 제공
  2. 상태 변수를 업데이트 하면 컴포넌트 다시 렌더링 하기 위한 상태 업데이트 함수 제공
const [상태, 상태변경함수] = useState(초기값)

여기서 React Hook이란?

  • 리액트에서 제공한는 use로 시작하는 모든 함수
  • hook은 리액트가 렌더링 되는 동안만 사용할 수 있음
  • 컴포넌트 또는 hook 함수 안에서만 사용 가능 (최상위 수준에서만 호출 가능)
  • 조건문, 반복문, 일반 함수 안에서 사용 X

상태는 독립적인 비공개 데이터

  • 상태는 화면의 컴포넌트 인스턴스에 대한 지역 변수
  • 동일한 컴포넌트가 여러 번 렌더링 되더라도 각 인스턴스는 격리된 상태
    즉, 여러 개 중 하나의 상태를 변경해도 다른 상태는 영향이 없음
  • 상위 컴포넌트에서는 접근 및 조작 불가능
  • 상태들을 동기화 하려면?
    • 동기화하려는 상태를 가진 컴포넌트에 부모 컴포넌트로 상태를 끌어올리면 됨 (Lifting state up)


리액트 렌더링 프로세스

초기 렌더링

render 함수

  • 리액트에서 초기 렌더링을 다루는 함수
  • 컴포넌트가 어떻게 생겼는지 정의하는 역할
  • html 형식의 문자열이 아닌, 뷰가 어떻게 생겼고 어떻게 작동하는지에 대한 정보를 지닌 객체를 반환(이것이 React Element)

📍 참고)
클래스 방식 컴포넌트
: Component 클래스를 상속받아 render 메서드를 사용하여 JSX를 반환

함수 방식 컴포넌트
: 함수를 사용하여 JSX를 직접 반환합니다.

두 컴포넌트 모두 <div>, <h1>, <p> 등의 JSX 요소를 반환
이렇게 반환된 JSX는 리액트 엘리먼트로 해석되어 리액트 엔진에 의해 처리되고 화면에 렌더링

// 클래스 방식 컴포넌트
import React, { Component } from 'react';

class ClassComponent extends Component {
  render() {
    return (
      <div>
        <h1>안녕</h1>
        <p>나는 클래스 방식 컴포넌트야</p>
      </div>
    );
  }
}

export default ClassComponent;
// 함수 방식 컴포넌트
import React from 'react';

const FunctionComponent = () => {
  return (
    <div>
      <h1>안녕</h1>
      <p>나는 함수 방식 컴포넌트야</p>
    </div>
  );
}

export default FunctionComponent;

컴포넌트는 html 태그를 반환하는것 처럼 보이지만
React Element를 반환함

React Element

: 해당 컴포넌트가 렌더링 하고자 하는 UI의 모든 정보를 가지고 있는 객체

프로젝트에 모든 React Element를 모아서 Virtual DOM을 만든다

Virtual DOM

  • 실제 DOM 아님
  • React Element 객체값들을 모은 것
    즉, JavaScript 객체값이다.
    그래서 수정, 삭제 등이 자유롭고 연산이 오래 걸리지 않는다.

만들어진 Virtual DOM을 실제 DOM에 반영해서 브라우저 렌더링한다.



리렌더링

리액트에서 수정사항이 생기면 React Element를 만드는 것부터 다시 시작해서 새로운 Virtual DOM을 만든다.
그리고 이전에 만든 Virtual DOM과 차이를 비교한다.
차이가 있는 부분만 실제 DOM에 반영한다. (이렇게 모아서 한번만 DOM을 수정)
이러한 과정을 조화(Reconciliation)라고 함

결국 방식 자체는 처음부터 다시 렌더링하는 것처럼 보이지만
사실은 최적의 자원을 사용하여 수행함

0개의 댓글