<Demopeu/>

react 학습하기 - UI 표현하기

react 학습하기 - UI 표현하기

referencereactUIcomponentrendering공식 문서

연말에 React를 돌아보는 시간을 가지고 있는데 정리 내용을 저장하려고 한다.

1️⃣ 첫 번째 컴포넌트

📌 컴포넌트

컴포넌트: UI 구성 요소

React를 사용하면 마크업, CSS, JS를 앱의 재사용 가능한 컴포넌트로 구성할 수 있다.

📌 컴포넌트 정의하기

  1. 컴포넌트 내보내기 : export default 접두사는 표준 JS 문법. 이 접두사를 사용한다.

  2. 함수 정의하기 : function 함수명() {}을 사용하면 JS 함수 정의할 수 있다. 이때 함수명은 대문자로 시작해야한다. 아니면 작동하지 않는다.

  3. 마크업 추가하기 : JSX 문법 사용한다. 컴포넌트는 다른 컴포넌트를 렌더링 할 수 있지만, 그 정의를 중첩해서는 안된다.

📊 챌린지 리뷰

export default function Profile() {
  return;
  <img src="https://i.imgur.com/jA8hHMpm.jpg" alt="Katsuko Saruhashi" />;
}
  • 유명한 함정. 자동으로 세미콜론을 넣어서 return문이 끝난 것으로 인식.
  • 따라서 한줄로 하거나 소괄호로 묶어주면 됨.

2️⃣ 컴포넌트 import 및 export 하기

컴포넌트의 가장 큰 장점은 재사용성으로 컴포넌트를 조합해 또 다른 컴포넌트 만들 수 있다는 것이다.

React에서는 './Gallery.js' 또는 './Gallery'로 import 할 수 있다. 전자의 경우가 native ES Modules 사용법에 더 가깝다고 할 수 있다.

📌 Default와 Named Exports

Syntax Export 구문 Import 구문
Default export default function Button() {} import Button from './button.js';
Named export function Button() {} import { Button } from './button.js';

보편적으로 한 파일에서 하나의 컴포넌트만 export 할 때 default export 방식을 사용하고, 여러 컴포넌트를 export 할 경우엔 named export 방식을 사용한다.

3️⃣ JSX로 마크업 작성하기

JSX는 JavaScript를 확장한 문법으로, HTML과 유사하지만 JavaScript의 특성을 유지한다.

매번 변화가 생길 때마다 서로 동기화 상태 유지할 수 있어서 편리하다.

📌 JSX의 규칙

  1. 반드시 하나의 루트 엘리먼트로 반환하기

    HTML처럼 보이지만 내부적으로는 react element라는 순수 js 객체로 변환된다. 하나의 함수에서는 두개의 객체를 반환 할 수 없기 때문이다.

  2. 모든 태그 닫아주기

  3. 대부분 camelCase 케이스로(틀려도 콘솔에서 알려준다)

4️⃣ 중괄호가 있는 JSX 안에서 자바스크립트 사용하기

JSX 안에서 중괄호를 사용하면 자바스크립트 표현식을 사용할 수 있다.

📌 중괄호를 사용하는 곳

  1. jsx 태그 안의 문자.
  2. = 바로 뒤에 오는 어트리뷰트

📌 이중 중괄호 사용하기

jsx에서 객체를 전달하려면 중괄호 쌍으로 객체를 감싸야한다. 인라인 css스타일에서 style 어트리뷰트에 객체를 전달해야한다. 이때 camelCase로 작성해야만 한다.

<img
  className="avatar"
  src={`${baseUrl}${person.imageId}${person.imageSize}.jpg`}
  alt={person.name}
/>

5️⃣ Props 전달하기

React 컴포넌트는 props를 통해 서로 통신한다. props는 객체, 배열, 함수를 포함한 모든 JS 값을 전달 할 수 있다.

  • props를 선언할 때, ()안에 {} 쌍을 놓치면 안된다.

  • 기본값 지정하기 {name = 'Stranger'}

  • 때때로 전달되는 props는 반복적일 수 있다. 이때 간결함이 중요할 때도 있다. 이때는 {...props}하면 간편하게 전달 된다.

props는 컴퓨터 과학에서 "변경 할 수 없다"라는 불변성을 가지고 있다. 따라서 변경할 때는 새로운 객체를 전달하도록 요청해야 한다. 그러면 js엔진은 기존 props가 차지했던 메모리 회수한다.

function Child(props) {
  props.color = "red"; // ❌ 이렇게 재할당하면 안 됨
  props.user.name = "동현"; // ❌ 객체 props 내부를 직접 mutate하는 것도 안 됨

  return <div>{props.color}</div>;
}

6️⃣ 조건부 렌더링

if (isPacked) {
  return null;
}
return <li className="item">{name}</li>;

return null은 흔하니까 걱정 말고 써도 된다.

📌 논리합 AND(&&)

피연산자를 왼쪽에서 오른쪽으로 평가하면서 첫 거짓 같은 피연산자를 만나면 반환. 모든 값이 참이면 마지막 값 반환.

&&의 왼쪽에 숫자를 두지마라

js는 자동으로 왼쪽을 boolean으로 변환. 예를 들어, 흔하게 하는 실수로 messageCount && <p>New messages</p>와 같은 코드를 작성하는 것. 메시지 카운트가 0일 때 아무것도 렌더링하지 않는다고 쉽게 추측할 수 있지만, 실제로는 0 자체를 렌더링함!

📌 react가 무시하는 값들

jsx 안에서 {...}에 넣을 때 null, undefined, false,true는 아에 렌더링 되지 않음.

7️⃣ 리스트 렌더링

화살표 함수는 암시적으로 => 바로 뒤에 식을 반환하기 때문에 return 문이 필요하지 않는다.

const listItems = chemists.map((person) => <li>...</li>); // 암시적 반환!

하지만 => 뒤에 { 중괄호가 오는 경우 return을 명시적으로 작성해야 한다!!

const listItems = chemists.map((person) => {
  // 중괄호
  return <li>...</li>;
});

=> { 를 표현하는 화살표 함수를 block body를 가지고 있다고 말한다. 이 함수를 사용하면 한 줄 이상의 코드를 작성할 수 있지만 return 문을 반드시 작성해야 한다. 그렇지 않으면 아무것도 반환되지 않는다!

map() 호출 내부의 JSX 엘리먼트에는 항상 key가 필요하다.

짧은 <> </> fragment 구문으로는 key를 전달할 수 없으므로 key를 단일 <div>로 그룹화하거나 약간 더 길고 명시적인 <Fragment> 문법을 사용을 권장.

📌 key 규칙

  1. key는 형제 간에 고유해야한다. 하지만 같은 key를 다른 배열의 jsx노드에 동일한 key로 사용해도 된다.
  2. key는 변경되면 안된다.
  3. 인덱스를 key로 사용하는 것은 권장하지 않는다.
  4. key={Math.random()}은 안된다. 매번 DOM이 새로 생성됨.

📌 목록태그

  1. 비 정렬 목록 태그: <ul></ul>
  2. 정렬 목록 태그: <ol></ol>
  3. 목록 항목 태그: <li></li>
  4. 정의 목록 태그: <dl></dl>
  5. 정의 태그: <dt></dt>
  6. 정의 내용 태그: <dd></dd>

8️⃣ 컴포넌트를 순수하게 유지하기

📌 순수 함수

순수 함수는 자신의 일에 집중한다. 함수가 호출되기 전에 존재했던 어떤 객체나 변수는 변경하지 않는다.

같은 입력, 같은 출력. 같은 입력이 주어지면 항상 같은 결과를 반환한다.

📌 사이드 이펙트

함수가 리턴값 말고 바깥 세상에 영향을 주거나, 바깥 것에 의존하는 행동

React의 렌더링 과정은 항상 순수해야 한다. React에서, 사이드 이펙트는 보통 이벤트 핸들러에 포함시킨다.

export default function Clock({ time }) {
  const hours = time.getHours();
  if (hours >= 0 && hours <= 6) {
    document.getElementById("time").className = "night";
  } else {
    document.getElementById("time").className = "day";
  }
  return <h1 id="time"> {time.toLocaleTimeString()} </h1>;
}

이 코드는 순수하지 않다. 왜냐하면 document.getElementById('time')를 사용하여 DOM을 직접 수정하고 있기 때문이다. react가 모르는 DOM 변경은 하지마라!

9️⃣ 트리로서의 UI

📌 렌더 트리

현재 UI의 스냅샷

렌더 트리 : 지금 이 순간 화면을 만들기 위해 React가 들고 있는 컴포넌트 구조, React 컴포넌트 단위로 구성.

📌 모듈 의존성 트리

파일의 관계 지도

모듈 의존성 트리: React 컴포넌트 단위가 아닌 import 된 모듈 단위로 구성.

모듈 의존성 트리의 중요성

  • 하나의 번들로 묶을지
  • route 단위로 쪼갤지 (코드 스플리팅)
  • 동적 import 경계를 어디로 잡을지
  • 공통 모듈을 별도 청크로 뺄지

번들러가 분석하는데 큰 도움을 준다.

따라서, React를 잘 이해하려면,

  • 렌더 트리를 보고

    • 상태 어디에 두는게 좋은지
    • 어떤 부분이 자주 리렌더 되는지
    • 성능 최적화를 어디에 적용할지

    이해해야 하고,

  • 모듈 의존성 트리를 보고

    • 번들 크기
    • 청크 구조

    이해하고 튜닝할 수 있어한다.