공부/React

리액트 입문주차 1주차 - 5

뀨뿌뀨뿌 2023. 6. 29. 14:34

1. Component

ⅰ. Component란?

  • 컴퍼넌트는 리액트의 핵심 빌딩 블록 중 하나
  • 리액트에서 개발한 모든 애플리케이션은 컴포넌트라는 조각으로 구성됨
  • 컴포넌트는 UI 구축 작업을 훨씬 쉽게 만들어줌
  • 컴포넌트란 리액트의 핵심 빌딩 블록 중 하나로 UI 요소를 표현하는 최소한의 단위이며 화면의 특정부분이 어떻게 생길지 정하는 선언체!
  • 리액트의 컴포넌트기반 개발 이전에는 브라우저에서 동적으로 변하는 UI를 표현하기 위해 직접 DOM 객체를 조작하는 명령형 프로그래밍 방식으로 구현
    => 직접 조작하는 방법(ex. querySelector, id나 class가지고 해당 하는 것을 찾음)
명령형은 어떻게(How)를 중요시 여겨서 프로그램의 제어 흐름과 같은 방법을 제시하고 목표를 명시하지 않는 형태
선언형은 무엇(What)을 중요시 여겨서 제어의 흐름보다는 원하는 목적을 중요시 여김
  • DOM(명령형 프로그래밍)
    • 명령형으로 작성된 코드의 경우 컴퓨터가 수행하는 절차를 일일히 코드로 작성해주어야함
// Hello, World! 화면에 출력하기
// 순수 javaScript 명령형 코드
const root = document.getElementById('root'); 
const header = document.createElement('h1'); 
const headerContent = document.createTextNode(
	'Hello, World!'
);

header.appendChild(headerContent); 
root.appendChild(header);
  • 리액트(선언형 프로그래밍)
    • UI를 선언하고 render함수를 호출하면 React가 알아서 절차를 수행해 화면에 출력해줌
    • 화면에 어떻게 그려야할지는 React 내부에 숨겨져 추상화 되어 있음
      =>리액트 안에서 어떻게 그려야 할지는 이미 정해져 있다(JSX문법으로)
// React 코드 (선언적인)
const header = <h1>Hello World</h1>; // jsx
ReactDOM.render(header, document.getElementById('root'));

 

❗❗ DOM을 직접 조작하여 명령형 프로그래밍 방식으로 작성하던 코드가 나쁘다는게 아님
코드가 너무나도 길어지게 되면 관리하기가 어려워지게 되어서 이러한 관리 도구들이 생겨남

ⅱ.  렌더링이란?

  • 컴포넌트가 현재 props와 state의 상태에 기초하여 UI를 어떻게 구성할지 컴포넌트에게 요청하는 작업을 의미
    => 데이터에 근거해서 UI를 어떻게 구성할지 컴포넌트에 요청하는것!!

  •   UI - 음식, 컴포넌트 - 음식을 만드는 주방장, 리액트 - 웨이터
    • 렌더링 일어나는 프로세스 
      1. 렌더링을 일으키는 것은 (triggering) - UI를 주문한다음에 주방으로 전달
      2. 렌더링을 한다는것(rendering) - 주방안에서 컴포넌트가 UI를 만들고 준비하는 것
      3. 렌더링 결과는 실제 DOM에 커밋한다는 것(commit) - 리액트가 준비된 UI를 손님테이블에 올려놓는것
      ✔ 프로그래밍에서 commit한다는 것은 대부분 done상태를 의미(완료된 상태)
  • 렌더링 트리거
    • 첫 리액트 앱을 실행할때
    • 현재 리액트 내부에 어떤 상태(state)에 변경이 발생했을 때
      • 컴포넌트 내부 state가 변경
      • 컴포넌트에 새로운 props가 들어올 때
      • 상위 부모 컴포넌트에서 위에 두 이유로 렌더링이 발생했을 때

리액트 앱이 실행되고 첫 렌더링이 일어나면 리액트는 컴포넌트의 루트에서 시작하여 아래쪽으로 쭉 훑으며 컴포넌트가 반환하는 JSX 결과물을 DOM요소에 반영함

ⅲ. 리렌더링

  • 첫 렌더링은 자동으로 일어난것
  • 첫 렌더링을 끝난 이후 추가로 렌더링을 트리거 하려면 사태를 변경해주면 됨
  • setState함수만 다뤘지만 몇가지 더 있음
  • 컴포넌트 상태에 변화가 생기면 리렌더링이 발생하는데 여러 상태가 변경됐다면 리액트는 이를 큐 자료구조에 넣어 순서를 관리함

  • 1.리렌더링은 음식점 손님이 첫 주문 이후에 추가로 주문하거나 새로운 메뉴를 주문하는 것과 같음
    2. 새로운 UI주문(리렌더링)이 일어나면 리액트가 변경된 내용을 주방에 있는 요리사인 컴포넌트에 전달하고 컴포넌트는 새로 변경된 주문으 토대로 새로운 요리(UI)를 만듦
    3. 새롭게 만들어진 요리(렌러딩 결과)는 리액트에 의해 다시 손님 테이블에 올려짐(DOM에 반영 - commit phase)
  • 브라우저 렌더링
    • 브라우저의 렌더링과 리액트의 렌더링은 다른 독립적인 프로세스
    • 렌더링이 완료되고React가 DOM을 업데이트한 후 브라우저는 화면을 그림
    • 이 프로세스를 "브라우저 렌더링" 이라고 하지만 혼동을 피하기 위해 "페인팅"이라고도 함

2. 반복되는 컴포넌트 처리하기

ⅰ. map과 filter

  • mpa함수는 기존의 것을 가공하여 출력하는 방법
    • map 함수를 쓸 때는 항상 key라는 prop이 필요함
    • map함수를 쓸때는 반복되는 요소가 출력되므로 요소에 id값을 붙여줘야함(고유 식별)
import React from "react";
import "./App.css";

const App = () => {
  const users = [
    { id: 1, age: 30, name: "송중기" },
    { id: 2, age: 24, name: "송강" },
    { id: 3, age: 21, name: "김유정" },
    { id: 4, age: 29, name: "구교환" },
  ];
  return (
    <div className="app-style">
      {users.map((item) => {
        return (
          <div key={item.id} className="component-style">
            {item.age} - {item.name}
          </div>
        );
      })}
    </div>
  );
};

export default App;

// Applcss
.app-style {
  padding: 100px;
  display: flex;
  gap: 12px;
}

.component-style {
  width: 100px;
  height: 100px;
  border: 1px solid green;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
}
  • filter함수는 조건에 만족하는 것만 출력하는 방법

ⅱ.  state 복습하기

// 기존 users 배열을 useState를 이용한 상태값 만들기
const [users, setUsers] = useState([
    { id: 1, age: 30, name: "송중기" },
    { id: 2, age: 24, name: "송강" },
    { id: 3, age: 21, name: "김유정" },
    { id: 4, age: 29, name: "구교환" },
  ]);

 

ⅲ. 추가 / 삭제를 위한 준비

....
  const [name, setName] = useState("");
  const [age, setAge] = useState("");

  const nameChangeHandler = (e) => {
    setName(e.target.value);
  };
  const ageChangeHandler = (e) => {
    setAge(e.target.value);
  };
  return (
    <div>
      <div>
        이름 :&nbsp;
        <input value={name} onChange={nameChangeHandler} />
        <br />
        나이 :&nbsp;
        <input value={age} onChange={ageChangeHandler} />
      </div>
      <div className="app-style">
        {users.map((item) => {
          return (
            <div key={item.id} className="component-style">
              {item.age} - {item.name}
            </div>
            .....

ⅳ.  user 추가

  const ClickButtonHandler = () => {
    // 1. 새로운 형태의 state를 만듦
    // 2. 배열에 더함
    const newUser = {
      id: users.length + 1,
      age,
      name: name,
    };
    // 불변성을 유지하기 위해서
    setUsers([...users, newUser]);
  };
  
  .....
  
          <input value={age} onChange={ageChangeHandler} />
        <br />
        <button onClick={ClickButtonHandler}>추가</button>
      </div>

ⅴ. user 삭제

....

  const clickRemoveButtonHandler = (id) => {
    const newUsers = users.filter((user) => user.id !== id);
    setUsers(newUsers)
  };
  
  ...
  
                {item.age} - {item.name}
              <button onClick={() => clickRemoveButtonHandler(item.id)}>
                X
              </button>

ⅵ. 컴포넌트 분리

// App.js
import React, { useState } from "react";
import "./App.css";
import Button from "components/Button";
import User from "components/User";

const App = () => {
  const [users, setUsers] = useState([
    { id: 1, age: 30, name: "송중기" },
    { id: 2, age: 24, name: "송강" },
    { id: 3, age: 21, name: "김유정" },
    { id: 4, age: 29, name: "구교환" },
  ]);
  const [name, setName] = useState("");
  const [age, setAge] = useState("");

  const nameChangeHandler = (e) => {
    setName(e.target.value);
  };
  const ageChangeHandler = (e) => {
    setAge(e.target.value);
  };
  const ClickButtonHandler = () => {
    // 1. 새로운 형태의 state를 만듦
    // 2. 배열에 더함
    const newUser = {
      id: users.length + 1,
      age,
      name: name,
    };
    // 불변성을 유지하기 위해서
    setUsers([...users, newUser]);
  };

  const clickRemoveButtonHandler = (id) => {
    const newUsers = users.filter((user) => user.id !== id);
    setUsers(newUsers);
  };

  return (
    <div>
      <div>
        이름 :&nbsp;
        <input value={name} onChange={nameChangeHandler} />
        <br />
        나이 :&nbsp;
        <input value={age} onChange={ageChangeHandler} />
        <br />
        <Button ClickButtonHandler={ClickButtonHandler}>추가</Button>
      </div>
      <div className="app-style">
        {users.map((item) => {
          return (
            <User
              key={item.id}
              item={item}
              removeFun={clickRemoveButtonHandler}
            />
          );
        })}
      </div>
    </div>
  );
};

export default App;
// User.js
const User = ({ item, removeFun }) => {
  return (
    <div key={item.id} className="component-style">
      {item.age} - {item.name}
      <button onClick={() => removeFun(item.id)}>X</button>
    </div>
  );
};

export default User;
// Button.js
const Button = ({ ClickButtonHandler, children }) => {
  return <button onClick={ClickButtonHandler}>{children}</button>;
};

export default Button

'공부 > React' 카테고리의 다른 글

리액트 숙련주차 - 2  (0) 2023.06.30
리액트 숙련주차 - 1  (0) 2023.06.30
리액트 입문주차 1주차 - 4  (0) 2023.06.27
리액트 입문주차 1주차 - 3  (0) 2023.06.25
리액트 입문주차 1주차 - 2  (0) 2023.06.23