React 공식 문서 읽어보기 (1)

Snoop So·2023년 7월 15일
0

컴포넌트

  • 대문자로 써야 컴포넌트로 이해함. 아니면 JS로 인식
  • 하나만 가져올때 default, 여러 컴포넌트는 named export 사용
  • 이름 없는 컴포넌트는 디버깅하기 어려워서 권장되지 않음
  • JSX 문법에서는 태그를 하나로 감싸줘야 하는데, 이유는 하나의 배열로 감싸지 않은 함수에서는 두 개의 객체를 반환할 수 없음
  • aria-, data- 만 제외하고 모든 js 예약어 속성은 사용할 수 없음
  • prop을 사용하고 싶지 않다면 size={undefined}로 사용할 것
  • 전개 구문 사용. but 제한적으로 사용할 것
function Profile(props) {
  return (
    <div className="card">
      <Avatar {...props} />
    </div>
  );
}
  • null 반환도 가능함, 근데 지양할 것
if (isPacked) {
  return null;
}
return <li className="item">{name}</li>;
  • && 의 왼쪽에 0을 넣지 말 것. 즉, messageCount && <p>New messages</p> 이렇게 하면 안됨. 0을 렌더링 해버림. !!messageCount 는 가능.
  • 여러 개의 DOM 노드를 렌더링해야 할 때는 Fragment를 사용할 것
import { Fragment } from 'react';

// ...

const listItems = people.map(person =>
  <Fragment key={person.id}>
    <h1>{person.name}</h1>
    <p>{person.bio}</p>
  </Fragment>
);
  • 데이터베이스에서 데이터를 만들거나, crypto.randomUUID() 와 같은 uuid 패키지를 사용할 것
  • key는 형제간에 고유해야하고 변경되면 안됨. 배열의 index는 사용하면 안됨. key={Math.random()}와 같은 방법도 마찬가지. 렌더링하다마다 key 가 일치하지 않아 매번 모든 컴포넌트와 DOM이 다시 생성됨.
  • 컴포넌트는 key를 prop으로 받지 않음. React 자체에서 힌트로만 사용됨.

컴포넌트 순수성

  • jsx는 반드시 동일한 입력이 주어졌을 때 동일한 JSX를 반환해야 함
  • Strict Mode에서 개발할 때 각 컴포넌트를 두 번 호출하는 이유는 이 이유 때문이다.
  • 순수하지 않은 컴포넌트의 예시는 아래와 같음. 즉 외부에 의존하는 변수가 있으면 안된다. props으로 전달할 것.
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 />
      <Cup />
      <Cup />
    </>
  );
}
  • 이벤트 헨들러는 렌더링 도중에는 실행되지 않으므로 이벤트 핸들러는 순수할 필요 없음
  • 이게 중요한 이유는 컴포넌트 재활용, 렌더링 건너뛰기 때문. 깊은 컴포넌트 트리를 렌더링하는 도중 일부 데이터가 변경되면 시간 낭비하지 않고 렌더링을 재시작.

상호작용

  • In React, data that changes over time is called state.
  • react에서 정의하는 상태란 시간이 지남에 따라 변화하는 데이터임.
  • 이 변경이란 사용자와의 상호 작용 결과
  • 컴포넌트별 메모리가 존재함
  • 컴포넌트가 화면에 표시되기 전에 컴포넌트들은 React에서 렌더링되어야 함
  • Triggering -> Rendering -> Commiting
  • 일반 JS 변수와는 달리 React state는 스냅샷과 같음
  • 이미 갖고 있는 state 변수는 변경되지 않고 대신 리렌더링됨.
console.log(count);  // 0
setCount(count + 1); // Request a re-render with 1
console.log(count);  // Still 0!
  • 바로 상태가 업데이트 되지 않고 스냅샷 시점의 변수로 출력함
  • React는 state 업데이트 전 이벤트 핸들러의 모든 코드가 실행될 때까지 기다림
  • setNumber() 호출이 모두 완료된 이후에만 일어남
setNumber(0 + 1);
setNumber(0 + 1);
setNumber(0 + 1);
  • 위와 같이 처리하는 것을 batching이라고도 함
  • 업데이트를 바로바로 하고 싶다면 큐의 이전 state를 기반으로 다음 state를 계산하는 함수를 전달할 수도 있음 이것을 업데이터 함수라고 부름
<button onClick={() => {
    setNumber(n => n + 1);
    setNumber(n => n + 1);
    setNumber(n => n + 1);
  }}>+3</button>
  • state 변수를 설정하면 다음 렌더링이 큐에 들어감. 큐에 들어간 것들을 일괄처리하는 React.
 <button onClick={() => {
        setNumber(number + 1);
        setNumber(number + 1);
        setNumber(number + 1);
      }}>+3</button>
  • 위 결과는 1임
  • 업데이트 큐 직접 구현해보기!
    // TODO
https://codesandbox.io/s/es6uix?file=%2FprocessQueue.js&utm_medium=sandpack
  • 배치는 딱 이렇게 돌아감
export function getFinalState(baseState, queue) {
  let finalState = 0;

  for (let update of queue) {
    if (typeof update === "function") {
      finalState = update(finalState);
    } else {
      finalState = update;
    }
  }
  return finalState;
}

변이

  • state에 넣는 모든 객체는 읽기 전용으로 취급해야 함
  • React는 state 설정자를 사용하지 않으면 객체가 변이되었다는 사실을 알지 못함

렌더링 단계

  1. 앱을 시작하기 전에 다음과 같은 첫 렌더링이 시작됨
import Image from './Image.js';
import { createRoot } from 'react-dom/client';

const root = createRoot(document.getElementById('root'))
root.render(<Image />);
  1. 컴포넌트가 처음 실행되면 set 함수로 state를 업데이트하여 추가 렌더링을 시작함

렌더링이 촉발되면 React는 컴포넌트를 호출하여 화면에 표시할 내용을 파악함
이떄 컴포넌트가 다른 컴포넌트를 반환하면(즉 부모 컴포넌트이면) 함께 여러번 렌더링됨

  1. React가 DOM에 변경사항을 커밋
  • 초기 렌더링의 경우 React는 appendChild() DOM API를 사용하여 생성한 모든 DOM 노드를 화면에 표시
  • 리렌더링의 경우에는 필요한 최소한의 작업을 적용함
  1. 브라우저 페인트
  • 렌더링이 완료되면 리액트가 DOM을 업데이트한 후 브라우저는 화면을 다시 그림

0개의 댓글