Recording/멋쟁이사자처럼 BE 13기

[멋쟁이사자처럼 부트캠프 TIL 회고] BE 13기_28일차_"리액트 React"

LEFT 2025. 1. 10. 17:52

🦁멋쟁이사자처럼 백엔드 부트캠프 13기 🦁
TIL 회고 - [28]일차

🚀28일차에는 리액트를 배울 수 있었다. 이전에 조금 접했던 라이브러리이지만 토이 프로젝트로 빠르게 지나간 이유로 기초가 많이 부족했다. 또한 시간이 많이 지나 기억이 잘 안나기도 하였다.

리액트의 기초부터 배우게되면서 리액트의 상태변화라던지 DOM을 가상 DOM으로 사용하는 것들이

자바스크립트 라이브러리에서 리액트가 자주쓰이는 이유임을 알 수 있었다. 

회고를 진행하면서 다른 실습도 진행해봐야겠다고 느꼈다.


 

리액트 React

  • 리액트 js : 메타에서 개발한 “오픈소스 자바스크립트 라이브러리”
  • Angular, Vue.js 와 함께 프론트엔드에서 많이 쓰임
  • Virtual DOM (가상 문서 객체 모델)을 활용하여 업데이트해야하는 DOM 요소를 찾아
    그 부분만 업데이트하기때문에 리렌더링(화면을 다시 그리는 작업)이 잦은 동적 웹페이지에서는 빠른 성능을 보여줌
  • 리액트는 이 Virtual DOM에서 조작하고 있다가 바뀐 부분이 일어나면 이 바뀐 부분만 실제 Brower DOM 에 적용
  • 사용자는 “업데이트를 어떻게 할지”를 고민하지 않고 리액트에게 맡김으로써 성능도 빠르게 개선할 수 있음
  • 리렌더링
    ➡️작은 부분을 수정할때는 “그 부분만 수정하는게 나을 것”
    ➡️큰 부분을 수정할때는 “처음부터 다시 수정하는게 나을 것”
    리액트는 다시 그려주는 "리렌더링" 기능을 제공

  • 리액트의 기본단위 : 컴포넌트 Component
  • 웹페이지에서는 컴포넌트안의 컴포넌트처럼 조립해서 사용한다.
  • 리액트는 컴포넌트 안의 내용을 바꿀때 도와주는 역할을 한다.
  • 즉 매번 전체의 컴포넌트를 리렌더링하기에는 시간, 비용이 많이 들기때문에
    ➡️변화가 있는 특정 컴포넌트만 다시 그려주는 것(리렌더링)

  •  

❓Virtual DOM

➡️브라우저에서 실제로 보여지는 DOM이 아닌
자바스크립트가 갖고 있는 DOM을 그대로 만들어서 가상으로 가지고 있게됨

➡️실제 DOM트리를 바꾸지 않고 바꾸고 있다가 실제 DOM 화면이 바뀌어야하는 시점에 계산
디핑 Diffing : (실제 DOM과 가상 DOM이 (변경하기 전에서 변경한 후 DOM의 어떤 것이 바뀌었는지 빠른 속도로 계산

➡️이 과정들 이후 리렌더링 (Re-rendering)작업을 하여 변경사항을 저장하게 되는 것이다.


DOM (Document Object Model - 문서 객체 모델)

  • HTML DOM 객체 모델에서 document객체는 “웹 페이지”를 나타낸다.
  • 따라서 HTML페이지에서 객체들에 접근하려면 항상 document객체에 접근하는 것으로부터 시작한다.
  • ex. document.body.style.backgroundColor = red;

 

자바스크립트 라이브러리, 프레임워크 등장배경

  • 자바스크립트를 이용해 이벤트 핸들링을 할때 (처리해야할 이벤트, 관리해야할 상태값, 다양한 DOM 등)
    ➡️업데이트 규칙이 복잡해질 것이다.
  • 이를 해결하기 위해
    ➡️Ember, Backbone, AngularJS 등 프레임워크가 만들어졌고
    ➡️React 등의 라이브러리가 만들어졌다.

  • 각각 작동방식이 다르지만 자바스크립트의 특정 값이 바뀌면
    특정 DOM속성만 바뀌도록하여 업데이트 작업을 간소화한다는 특징이 있다.

리액트 설치

  • npx create-react-app first-react
    ➡️첫 프로젝트 생성 npx [생성명령] [프로젝트명]

  • npx 명령
    ➡️npm프로젝트의 npm 명령처럼 npx프로젝트를 생성하겠다는 명령

  • ❓npm vs npx
    ➡️npx는 기본적인 프로젝트 구조를 가지고 만들어진다는 차이점

 

리액트 구조

  • src폴더 안의 App.js가 가장 핵심

index.css

.card {
  background-color: white;
  border-radius: 4px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
  padding: 1rem;
  width: 20rem;
}
  • index.css에 css 스타일을 추가하고 추후 이 스타일을 사용할 div태그에 className="card"로 넣어줄 수 있을 것

index.js

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
  • createRoot(document.getElementById("root"))
    ➡️이 root는 public폴더 안에 있는 index.html의 <div id=”root”></div>태그를 얻어온 것
  • root.render(<App />);
    ➡️이 root태그에 .render{  } 로 App컴포넌트를 담아주었다. (이 안의 App컴포넌트는 App.js를 의미)

  • 이처럼 React DOM을 통하여 createRoot()이 가상 DOM을 만들어내고 있음을 알 수 있다.

App.js

function App() {
  return (
    <div>
      <h1>-----First React-----</h1>
      <p>Hello React!!</p>
    </div>
  );
}

export default App;
  • 리액트 요청 과정
    1. 리액트는 기본페이지인 index.html를 브라우저에 반영하여 보여주고
    2. index.js에서 index.html의 <div id="root"> 태그를 가져와서
    3. 컴포넌트들을 만들어낼때 이 컴포넌트들은 <div id="root">태그 안에 들어가게된다.
    4. 즉 리액트가 가장 큰 컴포넌트(=root 컴포넌트)라고 했을때 App.js에 다른 컴포넌트를 만들면(ex. 버튼, 텍스트..)
    5. root컴포넌트의 자식 컴포넌트로 있는 App.js 컴포넌트 안에 만들었던 컴포넌트들이 위치하게되는 것이다.

  • HTML 처럼 보이지만 사실 JSX라는 문법을 가진다.
    즉 return값으로 HTML 구조를 리턴하는 것 같지만 이를 JSX 문법이 쓰인 것이다.

컴포넌트 Component

  • 리액트는 function으로 컴포넌트를 만든다.
  • 파일의 이름은 컴포넌트와 같아야한다. (Counter.js === function Counter () === export default Counter;)
class App extends React.Component{ ... }
  • class 문법을 사용하여 컴포넌트 만드는 것도 가능한데
    ➡️여기서 확인해볼점은 React.Component를 상속받고 있다는 것이다.

function App(){ return ( ... ) }
  • 이 function 문법 사용 코드도 위의 class문법과 동일한 기능을 하는데
    ➡️위와 똑같이 컴포넌트를 만들어 return으로 화면에 보여주는 코드라고 볼 수 있다.
  • 💡리액트는 클래스 사용보다는 함수 문법 사용을 권장하고 있다.
const App = () => { return ( ... ) }
  • 함수 문법 사용을 더 개선하여 "화살표함수"로 컴포넌트를 만들 수 있을 것이다.

JSX

  • JSX는 문자열, HTML이 아니며 자바스크립트를 확장한 문법이다.
  • 문법 규칙 :
    ➡️root 요소는 1개여야한다.
    ➡️자바스크립트 값은 { }로 감싸서 출력한다. 반드시 return이 포함되어야한다.
    ➡️인라인 스타일은 객체 형태로 해야한다. (ex. background-color >> backgroundColor 카멜표기법 변환)
    ➡️ (class="클래스명") 이 아닌 (className="클래스명")으로 설정
    ➡️ { /_ 주석 _/ } 형태로 주석 작성
    ⭐중요 : 모든 요소들은 하나로 감싸져야한다. (=태그는 반드시 닫혀야한다)
    (div태그로 묶든, 다른 태그로 묶든 어느태그로든 무조건 하나 컴포넌트(=박스, 컨테이너)로 묶여야있어야한다)
  • Fragment
    ➡️<> </>처럼 아무것도 없는 태그로 감싸지는 것을 의미하며
    브라우저 상에서 따로 별도의 엘리먼트로 나타나지 않는다.

❓Fragment 사용 이유

➡️JSX태그는 상자로 반드시 묶여야있어야하기때문에 큰 의미 없는 태그인 Fragment를 사용하여 하나로 묶어줌을 표시
➡️실제 박스를 가지진 않지만 하나로 묶어줄 수 있는 기능을 제공

 

▶️실습 - JSX문법 (태그는 반드시 닫혀야한다)

<div>
  <h1>-----First React-----</h1>
  <p>Hello React!!</p>
</div>
<>
  <h1>-----First React-----</h1>
  <p>Hello React!!</p>
</>
  • 둘다 가능
return (
    <h1>-----First React-----</h1>
    <p>Hello React!!</p>
);
  • 불가능

JSX 작동원리

<div>
  <h1>-----First React-----</h1>
  <p>Hello React!!</p>
</div>
  • 사용자입장에서는 복잡하게 HTML 문법을 자바스크립트로 바꾸고 하는 과정이 없이
    JSX는 React의 Element(요소)를 생성하는 기능을 한다.

  • 리액트가 간단하게 HTML 문법처럼 쓰면 자바스크립트로 바꿔주는 역할을 하는 것이다.

  • React는 별도 파일에 HTML마크업과 자바스크립트 코드를 넣어 인위적으로 분리하는 대신
    이 둘을 모두 포함하는 “컴포넌트”라는 느슨하게 연결된 유닛으로 분리시킨다.

  • 👀만약 자바로 프로젝트를 진행할떄 실제 화면은 HTML코드로 만드는데
    코드들이 자바코드 안에 들어있어야한다면 이 HTML코드(=구조)를 자바코드로 바꿔주는 역할을 하는 것이 "JSP"

JSX문법 = (HTML + 자바스크립트) 동시 사용

const name = "Alexandar Isak";
const element = <h1>Hello, I'm {name}</h1>;
  • 이처럼 <h1>태그의 HTML과 {name}처럼 자바스크립트 문법을 같이 사용하는 것이 가능하다는 것이다.
function App() {
  const name = "Anthony Gordon";
  return (
    <div>
      <h1>-----First React-----</h1>
      <p>Hello React!!</p>
      <h3>Introduce</h3>
      <p>Hi, I'm {name}. Nice to meet you.</p>
    </div>
  );
}
export default App;
  • 프로젝트에 적용해보면 
    ➡️return 밖에서 const name을 정의
    ➡️return 안에서 <p>태그로 {name}처럼 값을 참조

  • 이처럼 HTML과 자바스크립트가 같이 쓰이므로 JSX문법은 HTML이 아닌 것을 알 수 있다.
  • return 안에 들어있는 것이 JSX문법이고, return 안에 들어있는 것들만 “화면에 보여지게 된다”

Babel

  • JavaScript transpiler/Compiler
  • 컴파일 : 인간의 소스코드를 컴퓨터가 이해할 수 있는 기계어(머신코드)로 바꿔주는 과정
  • 트랜스파일 : 다른 실행환경에서도 돌아갈 수 있도록 “같은 언어를 유지한채” 소스코드의 형태만 바꾸는 과정
  • Babel은 XML형태의 JSX를 “자바스크립트”로 변환(트랜스파일, transpile)해준다.


JSX → 자바스크립트 변환하는 과정 (브라우저)

  • 개발자 도구로 확인해보면 이 컴포넌트는 <div id=”root”> 태그 안에 <div class=”card”>처럼 들어와있다.
  • ⭐사용자는 JSX문법으로 className=”card”처럼 넣어주었지만 리액트가 “Babel”을 이용하여 자바스크립트 문법으로 브라우저에 적용하고 있는 것을 확인할 수 있다.

JSX → 자바스크립트 변환하는 과정 (Babeljs.io)

<div className="card">
  <h1>-----First React-----</h1>
  <p>Hello React!!</p>
  <h3>Introduce</h3>
  <p>Hi, I'm {name}. Nice to meet you.</p>
</div>
  • [변환 전] : JSX 문법

  • [변환 후] : Babel로 자바스크립트 문법 변환

▶️실습 - 컴포넌트들을 (카드 컴포넌트)에 담기

  • index.css 를 .card 코드로 변경 후 return부의 div태그에 className=”card” 로 CSS 스타일 적용

  • index.css의 background-color 속성을 수정하여 카드에 색을 넣어줄 수도 있을 것이다.

▶️실습 - 숫자 조작 버튼 만들기 (카운터 컴포넌트)

const Counter = () => {
  return;
  <div>
    <h2>0</h2>
    <input type="button" value="+" />
    <input type="button" value="-" />
  </div>;
};
  • 버튼만들기
    ➡️<input type=”button” value=”+”/>
    ➡️<button>+</button> 두 방법 모두 같은 기능을 한다.

  • export default Counter;
    ➡️외부모듈에서 이 Counter를 사용할 수 있도록하는 문법
    지금 Counter안에 작성한 코드들을 수행할 수 있도록 export를 해주어야함

▶️실습 - 카운터 컴포넌트 App 컴포넌트에 적용

function App() {
  const name = "Anthony Gordon";
  return (
    <div className="card">
      <h1>-----First React-----</h1>
      <p>Hello React!!</p>
      <h3>Introduce</h3>
      <p>Hi, I'm {name}. Nice to meet you.</p>
      <Counter>
        
      </Counter>
    </div>
  );
}
  • <Counter> </Counter>로 App() 컴포넌트에 넣어주어 사용을 명시한다. 또한 Counter컴포넌트를 import 해야한다.
    ➡️import Counter from “./Counter”;
    ➡️Counter안에 들어있는 모듈중에 Counter라는 것을 사용할 것이다. 라는 의미

  • 만약 Counter에 아무내용없이 넣고자한다면 <Counter /> 처럼 바로 태그를 닫아서 사용하는 것도 가능하다.

 

<Counter> 
	<자식컴포넌트> 
	</자식컴포넌트> 
</Counter>
  • Counter 컴포넌트 안에 자식 컴포넌트를 사용하고자할때 이처럼 Counter컴포넌트 안에 자식컴포넌트를 위치시킨다.

  • App.js 텍스트 컴포넌트 밑으로 (텍스트 0과 +, - 버튼) (=카운터 컴포넌트)가 추가된 것을 확인할 수 있다.
  • 초록색 카드 컴포넌트 안에 (0, +, - 버튼)이 담긴 카운터 컴포넌트가 위치한 것이다.

컴포넌트에 이벤트 설정

  • JSX문법으로 { } 중괄호 안에 들어오는 모든 것들은 자바스크립트 코드이다.
<input type="button" value="+" onClick={() => alert("hi")} />
  • JSX는 이벤트를 설정시 태그의 속성으로 onClick()을 지정해주고 안에 구현할 내용을 설정한다.
  • JSX에서 onClick()로 이벤트를 설정해주는 과정은
    리액트가 document.get… 으로부터 요소를 찾고 그 요소에 addEventListener()로 이벤트를 걸어주는
    자바스크립트 코드 변환 과정을 간단하게 해주는 것이라고 할 수 있다.

 

const Counter = () => {
  console.log("Counter 컴포넌트 실행!");
  let count = 0;

  const plusHandler = () => {
    count++;
  };

  const minusHandler = () => {
    count--;
  };
  return (
    <div>
      <h2>{count}</h2>
      <input type="button" value="+" onClick={plusHandler} />
      <input type="button" value="-" onClick={minusHandler} />
    </div>
  );
};

export default Counter;
  • onClick={함수이름} 을 설정하고
  • const plusHandler = () ⇒ { alert(”hi”); };
    ➡️ return 밖에서 함수를 정의해준 후 사용 가능
  • console.log("Counter 컴포넌트 실행!")
    ➡️App컴포넌트와 Counter컴포넌트에 “App 컴포넌트 실행!”, “Counter컴포넌트 실행!”을 작성해보면
    ➡️App 컴포넌트 실행! → Counter 컴포넌트 실행! 이 출력된 후
    ➡️버튼을 눌러 이벤트 처리로 count 값을 변경해주어도 실제 <h2>태그의 {count}에는 반영이 되지 않는다.

  • 그 이유는 HTML이 정적인 특징을 가지므로 브라우저에서 HTML을 한번 불러낸 후 연결을 끊어놓아서
    렌더링이 되지 않은 것이다.
    ➡️리렌더링(화면에 다시 그리는 과정)을 통해 상태값을 변화시킬 수 있어야한다.

  • 리액트는 “어느 시점에 리렌더링을 수행해야하는지”를 판단해야한다.
    ➡️그 시점은 count값이 변경되었을때, 즉 버튼이 눌렸을때 count값이 바뀌고 난 후일 것이다.
    ➡️해결방법 : useState 를 사용하여 상태관리 해야한다 (리액트의 Hook 중의 하나이며 가장 기본적인 훅)
    useState를 통해 함수 컴포넌트에서 값을 저장하여 갖고있는 것이 아니라 리액트가
    useState를 이용하여 count값을 가지고 있어야한다.

useState

  • React의 구현하고 있는 함수이자 가장 기본적인 Hook 중 하나로 함수 컴포넌트에서 “상태값을 관리하기 위해 사용”

리액트의 useState 함수 작동원리

  • useState : 상태(state)를 추가하기 위해 사용되는 훅 (Hook)
  • this.state or this.setState() 사용
    ➡️함수 컴포넌트 내부에서 상태를 관리할 수 있게 리액트가 도와줌
  • let count=0 처럼 지역변수로 사용하지 않고 리액트에게 count를 선언해주어야한다.
import { useState } from "react";

const Counter = () => {
  console.log("Counter 컴포넌트 실행!");
//   let count = 0;
useState
  • import { useState } from "react";
    ➡️let count = 0; 대신 useState를 사용하고자하면 useState가 import되는데
    많은 React 함수 중에 useState함수(=컴포넌트)를 쓰는 것이므로 { } 중괄호 안에 useState가 위치한다.

  • 즉 큰 컴포넌트 안(react)에서 특정 컴포넌트만(useState) 가져다 쓸 것임을 의미한다.
  • ex. export default Counter;
    ➡️Counter 컴포넌트를 기본으로 쓸 것임을 지정했다고 했을때
    ➡️Counter 컴포넌트 안에 removeValue 컴포넌트가 존재한다고하면 
import { removeValue } from "./Counter";
  • 다른 컴포넌트(App컴포넌트 등)에서 이 Counter컴포넌트 안에 있는 removeValue 컴포넌트를 이처럼 import한다.

useState 적용

const [count, setCount] = useSate(0);
  • useState(0) 호출
    ➡️[currentState, UpdaterFunction] 형태의 배열을 반환한다. [현재상태, 변화를 줄 함수] 형태
    ➡️count = 변수, setCount = 변화를 줄 함수, useState = 리액트에 상태를 알려주는 Hook

  • 추가로 useState 함수가 구현하고 있는 setState() 함수를 사용하여 상태를 업데이트해야한다.
  • Counter컴포넌트에서 구현했던 함수인 plusHandler() 와 minusHandler() 안에서
    ➡️setCount(count + 1), setCount(count - 1); 처럼 count값을 갱신한다.

  • const [ count, setCount ] 문법
    ➡️배열의 구조분해할당, 즉 비구조적 할당이 적용된 경우이다.

 

❓const로 선언하는 이유

➡️count값에 재할당이 필요없기 때문, 상태 값(count) 그 자체를 바꾸는 것이 아닌
React가 제공하는 “상태 갱신 함수”인 setCount를 통해 갱신되어야한다.

즉 count = 10; 대입이 아닌 setCount(10);을 호출하여 상태를 변경

따라서 렌더링마다 (const count)가 생기는 것이 아니라
리액트가 리렌더링 할때 useState함수가 반환하는 새로운 상태값을 count에 할당하기한다.
const를 사용하면 let 사용할때와 달리 다른 값에 재할당되는 예외상황에 대비할 수 있어 코드의 안전성을 높여주게된다.


▶️실습 - 리액트의 상태변화함수 useState를 적용한 카운터 컴포넌트

import { useState } from "react";

const Counter = () => {
  console.log("Counter 컴포넌트 실행!");
  //   let count = 0;
  const [count, setCount] = useState(0);

  const plusHandler = () => {
    setCount(count + 1);
  };

  const minusHandler = () => {
    setCount(count - 1);
  };
  return (
    <div>
      <h2>{count}</h2>
      <input type="button" value="+" onClick={plusHandler} />
      <input type="button" value="-" onClick={minusHandler} />
    </div>
  );
};

export default Counter;

  • useState를 추가하게 되어 버튼이 눌리면 count값에 변화가 생길때마다 리렌더링 작업을 수행하게된다.
    ➡️컴포넌트가 함수 역할을 하고 있음을 알 수 있다.

Props

  • Properties의 약자
  • 속성을 의미하며, <input type=”button” value=”+”/> 같은 태그에서는
    ➡️type과 value가 props를 의미한다.
// Props 실습
const MyButton = () => {
  return <button></button>;
};

export default MyButton;
  • 자식 컴포넌트(MyButton)가 부모 컴포넌트(Counter)로부터 Props(=Properties, =속성)을 받아서 사용하고자할때

Props - 객체로 받기

// Props 실습
const MyButton = (properties) => {
  return <button>{properties.title}</button>;
};

export default MyButton;
  • 인자로 객체(properties)를 전달받아서 properties.title 참조방식으로 title 속성에 접근할 수 있다.

❓Props를 사용하는 이유

➡️버튼에 나와야하는 텍스트가 버튼들마다 달라야하기때문에
<button>+</button> 처럼 계속 만들어서 사용하는 것보다 부모버튼이 사용하는 속성(ex.버튼제목)을 넘겨받아와
코드의 재사용이 가능하다.

이를 Props라고 하며 속성을 넘겨받아 사용함을 뜻한다.
부모는 여러개의 속성을 넘겨줄 수도 있기때문에 위 코드처럼 ( ) 안에는 “객체”로 넘어올 수 있게할 수 있다.
➡️const MyButton( ) 괄호 안에 부모컴포넌트로부터 넘어온 객체를 받을 “변수”를 선언

 

Props - 속성을 받기 (구조분해할당 (=비구조적 할당) 사용)

// Props 실습
const MyButton = ({title}) => {
  return <button>{title}</button>;
};

export default MyButton;
  • MyButton 컴포넌트를 Counter.js 컴포넌트에 추가해본다.
  • 아까 Counter내에서 만들어낸 버튼을 Props를 활용하여 컴포넌트를 분리한 후 여기저기 다른 컴포넌트에서도 쓰일 수 있게만드는 것이다.
  • const MyButton = ( { title} )
    ➡️중괄호 안에 인자로 title이라는 속성을 직접 가져오고
    ➡️사용시에도 {props.title}처럼 부모객체를 참조해서 사용하지 않고
    ➡️{title}로 직접 속성을 사용할 수 있다.

리액트 -  CSS 스타일 적용

const btnStyle = {
  color: "white",
  background: "teal",
  padding: ".375rem .75rem",
  margin: ".5rem",
  border: "1px solid teal",
};

const MyButton = (properties) => {
  return <button style={btnStyle}>{properties.title}</button>;
};

export default MyButton;

  • 리액트에서  CSS 스타일을 지정할때는 속성으로 style={ } 를 사용하고
    ➡️중괄호 안에 const로 정의한 css를 위치시킨다.

리액트 - 이벤트 적용

  • 버튼을 눌렀을때의 useState를 통해 count값이 변화하는 이벤트는 발생하지 않고 있다.
  • 이 때 이벤트는 자식컴포넌트(MyButton)가 아닌 부모컴포넌트(Counter)가 가지고 있어야한다.
    즉 부모컴포넌트(Counter)가 가지고 있는 이벤트를 자식컴포넌트(MyButton)가 사용해야한다.
const MyButton = (props) => {
  return <button style={btnStyle} onClick={props.clickHandler}>{props.title}</button>;
};
  • 참조명을 간단히 표시하기 위해 properties → props로 변경
  • onClick = { } 안에는 받아온 객체에서 정의되어있는 속성 중 clickHandler 이벤트를 가져와야한다.
    ➡️(이벤트이름 지정은 자유)
const MyButton = ( {title, clickHandler} ) => {
  return <button style={btnStyle} onClick={clickHandler}>{title}</button>;
};
  • 위의 코드를 구조분해할당을 통해 { } 안에 직접 속성을 넣어 이처럼 사용할 수도 있다.
return (
    <div>
      <h2>{count}</h2>
      {/* <input type="button" value="+" onClick={plusHandler} />
      <input type="button" value="-" onClick={minusHandler} /> */}
      <MyButton title="+" clickHandler={plusHandler}/>
      <MyButton title="-" clickHandler={minusHandler}/>
    </div>
);
  • Counter 부모컴포넌트(Counter)는 clickHandler라는 속성의 속성값으로 { } 안에 미리 정의해놨던 함수를 넣어보낸다.

실행결과 정상


▶️실습 - 안녕 버튼 만들기

const byeHandler = () => {
    alert("안녕히계세요.🥲");
  };
  return (
    <div>
      <h2>{count}</h2>
      <MyButton title="+" clickHandler={plusHandler} />
      <MyButton title="-" clickHandler={minusHandler} />
      <MyButton title="Goodbye" clickHandler={byeHandler} />
    </div>
  );
  • 부모컴포넌트(Counter) 안에 함수를 직접 추가하고 속성으로 보낼 수 있다.
<MyButton title="Goodbye" clickHandler={() => alert("안녕히계세요.🥲")} />
  • 위의 코드를 개선하여 화살표함수를 사용하면 함수를 별도로 만들어 정의하지 않고 바로 전달할 수도 있다.

❓리액트의 Props사용

➡️자바스크립트에서 “부모태그” 요소를 받아서 “자식태그”요소를 생성한 후
부모태그에 appendChild()로 추가 과정들이 간략화된것이다.


브라우저에 보여지는 첫 화면 수정

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
  • index.js에서 render(<App />); 처럼 불러와지는 부분을
  • 다른 js 컴포넌트로 바꾸면 기본값으로 그 컴포넌트를 불러오도록 설정할 수 있을 것이다.

 

root컴포넌트(최상위) 안의 컴포넌트 순서 수정

  • App 컴포넌트에서 Counter 컴포넌트들 밑에 MyButton을 하나 더 만들어서 컴포넌트 순서가 적용되는지 확인해본다.
<div className="card">
  <h1>-----First React-----</h1>
  <p>Hello React!!</p>
  <h3>Introduce</h3>
  <p>Hi, I'm {name}. Nice to meet you.</p>
  <Counter></Counter>
  <MyButton title="Counter밑 버튼" />
</div>

  • <Counter></Counter>
    ➡️MyButton컴포넌트들 (+Goodbye 컴포넌트 포함) 이 존재하고

  • <MyButton title="Counter밑 버튼" />
    ➡️그 밑으로 새로운 MyButton컴포넌트 (”Counter밑 버튼”)이 위치할 수 있게 순서를 두었다.

Props 사용시 주의점

  • props는 읽기전용이므로 입력되는 값을 변경하면안된다.
  • 리액트의 모든 컴포넌트는 자신의 props를 다룰때 “순수함수”처럼 동작해야한다.
    ➡️순수함수 : ex. sum(a, b) 함수는 return a + b를 반환하므로 입력값인 a, b값을 바꾸지 않는다.
    ➡️순수함수가 아닌 경우 : ex. withdraw(account, amount) 함수return account.total -= amount; 입력값을 바꾼다.

▶️실습 - 여러개의 props 할당

부모컴포넌트 (App컴포넌트)

function App() {
    return (
        <MyButton title="컬러테스트" color="red"/>
    );
}
export default App;

자식컴포넌트 (MyButton컴포넌트)

function MyButton(props){
	return <div style={ { color: props.color } }> 버튼 색 설정 {props.title}</div>
}
export default MyButton;
  • 부모컴포넌트로부터 color속성을 받아와서 style=을 지정
  • style={ } 은 기본적으로 자바스크립트 코드를 사용하므로 중괄호를 가진다.
  • style={ } 중괄호는 “자바스크립트 코드”를 나타내고
    ➡️style={ { color: props.color} } 처럼 안쪽의 중괄호는 “객체의 참조를 나타낸다”
    ➡️이는 비구조화 할당 방식을 사용하여 간단하게 표현 가능

▶️실습 - 여러개의 props 할당 - 비구조화 할당 방식 사용

function MyButton( { color, title } ){
    return <div style={ { color } }> 버튼 색 설정 {title}</div>
}
export default MyButton;
  • 비구조화 할당방식 사용으로 부모컴포넌트로부터 객체가 아닌 여러개의 속성이 넘어올때 { } 안에 지정
  • 부모컴포넌트를 참조하는 props.color 코드처럼 사용하지 않고 단순히 color적용, title도 마찬가지

Props - 기본값 지정

부모컴포넌트 (Counter컴포넌트)

<MyButton />
  • 부모 컴포넌트에서 아무 속성(Props)이 들어오지 않았을때
    기본으로 설정할 값을 자식 컴포넌트에서 설정해줄 수 있다.

자식컴포넌트 (MyButton컴포넌트)

MyButton.defaultProps = {
    title: "기본 버튼",
    clickHandler: () => alert("기본 출력"),
};
  • 자식 컴포넌트에서 이처럼 defaultProps 를 설정
    ➡️부모로부터 넘어온 속성에 속성값이 없을때 설정하는 기본값

조건부 렌더링

  • isSpecial Props(속성) 사용
<MyButton title=”조건버튼” isSpecial={false} />
  • 조건실행 false, true값에 따라 실행유무를 판단 

🚀실습 - 주문하기 컴포넌트

 

부모컴포넌트 (App컴포넌트)

function App() {
  console.log("App 컴포넌트 실행!");
  return (
    <div className="card">
      <Order title="주문하기"></Order>
    </div>
  );
}

자식컴포넌트 (Order컴포넌트)

const Order = ({ title }) => {
  console.log("Order 컴포넌트 실행! 📞");
  return (
    <div>
      <h3>-주문하기-</h3>
      <button onClick={() => alert("주문완료!📞")}>{title}</button>
    </div>
  );
};

export default Order;

  • App에서 지정한 title props만 가져다가 버튼의 타이틀로 사용하고
  • onClick 이벤트는 자식컴포넌트에서 화살표함수로 직접 지정해주었다.

🚀 배운내용이 많은 회고였다. 회고를 진행하면서 빠르게 지나쳤던 부분들을 다시 상기하고 공부할 수 있었다.

부모컴포넌트, 자식컴포넌트 관계로 Props를 넘기는 부분이 인상적이었다.

자바에서 클래스의 인스턴스를 생성하고 그 인스턴스를 참조하여 메소드를 사용했던 것이 떠오르기도 하였다.

리액트의 문법들이 생소하지만 유용한 기능을 하고 있음을 깨닫게 되었다.