(준)공식 문서/React

[ React 공식문서 ] UI 구상하기 (8) : 컴포넌트 순수성 유지

Je-chan 2024. 2. 27. 23:21

React는 컴포넌트를 엄격하게 순수 함수로 작성하도록 강제한다

그렇기에 React 코드를 짤 때 몇 가지 규칙을 준수해야만 한다.

1. 순수성 : 수식으로서의 컴포넌트

컴퓨터 과학에서 순수 함수는 다음의 특징을 지닌다.

  1. 자신의 일에만 신경 쓴다
    : 호출되기 전에 존재했던 객체나 변수를 변경하지 않는다
  2. 동일한 값을 입력 받으면 항상 동일한 결과를 반환해야 한다.
    : 컴포넌트가 이런 순수성을 유지한다고 하는 건 어떤 데이터를 받든, 그 데이터를 받을 때마다 항상 동일한 화면을 보여줘야 함을 의미한다.

2. 사이드 이펙트

React 렌더링 프로세스는 항상 순수해야 한다.

: 컴포넌트는 JSX 만을 반환해야 한다.

: 렌더링 존재한 객체나 변수를 변경해서는 안 된다.

let guest = 0;

function Cup() {
  // Bad: changing a preexisting variable!
  // 나쁨: 기존 변수를 변경합니다!
  guest = guest + 1;
  return <h2>Tea cup for guest #{guest}</h2>;
}

export default function TeaSet() {
  return (
    <>
      <Cup /> {/* guest: 2*/}
      <Cup /> {/* guest: 4*/}
      <Cup /> {/* guest: 6*/}
    </>
  );
}

 

CUP 컴포넌트는 guest 라는 외부에서 선언된 변수를 읽고 쓰고 있다.

이 말은 이 컴포넌트가 호출할 때마다 다른 JSX 를 생성한다는 것을 의미한다.

그리고, 렌더링된 시점에 따라 JSX 도 다르게 생성된다

그렇기 때문에 CUP 에서 렌더링하는 guest 의 수가 개발자가 의도한 것과는 다르게 나온다 (아마 개발자가 의도한 바는 1, 2, 3 일 것이다)

동일한 컴포넌트에서 다른 값이 렌더링돼야 한다면, 이 때는 prop 을 사용해서 부모로부터 값을 전달받아야 한다.

 

function Cup({ guest }) {
  return <h2>Tea cup for guest #{guest}</h2>;
}

export default function TeaSet() {
  return (
    <>
      <Cup guest={1} />
      <Cup guest={2} />
      <Cup guest={3} />
    </>
  );
}

 

이제 컴포넌트가 반환하는 JSX 는 guest 라는 prop 에만 의존하기 때문에 순수하다


3. 지역 변이 (Local Mutation)

위의 예시에서 발생한 문제는 컴포넌트가 렌더링 하는 동안 기존 변수를 변경하는 것이었다.

하지만, 렌더링 하는 동안에 방금 생성한 변수와 객체를 변경하는 것은 문제가 되지 않는다.

즉, 컴포넌트 함수 내부에서 생성한 변수와 객체를 변경하는 것은 문제가 안 된다

 

function Cup({ guest }) {
  return <h2>Tea cup for guest #{guest}</h2>;
}

export default function TeaGathering() {
  let cups = [];
  for (let i = 1; i <= 12; i++) {
    cups.push(<Cup key={i} guest={i} />);
  }
  return cups;
}

 

여기에서 만약, cups 나 배열이 TeaGathering 외부에서 생성됐다면 에러를 발생시켰을 것. 하지만, 렌더링 중에 생성된 변수이므로 아무런 문제가 되지 않는다


4. 사이드 이펙트를 일으킬 수 있는 곳

React 에서 사이드 이펙트는 보통 이벤트 핸들러에 속한다

이벤트 핸들러란 사용자가 동작을 수행할 때 React 가 실행하는 함수다.

 

이 이벤트 핸들러가 컴포넌트 내부에 정의되어 있더라도 렌더링 중에는 실행되지 않는다

그러므로 이벤트 핸들러는 굳이 순수할 필요가 없다

 

문제는, 렌더링 중에 실행되는 함수기 때문

 

만약 사이드 이펙트에 적합한 이벤트 핸들러가 없다면, useEffect 호출을 통해서 JSX 에 이벤트 핸들러를 첨부할 수 있다

: 하지만, 이 방법은 최후의 수단으로 활용할 것

: 웬만하면 렌더링 만으로 로직을 표현하기 위해 노력해야 한다

 


Reference

https://react.dev/learn/keeping-components-pure

 

Keeping Components Pure – React

The library for web and native user interfaces

react.dev

https://react-ko.dev/learn/keeping-components-pure

 

컴포넌트 순수성 유지 – React

The library for web and native user interfaces

react-ko.dev