[React] Components와 Props

 

 

01

Components

- Component란 웹 페이지의 한 부분을 나타내는 코드 블럭이며 재사용이 가능한 UI 요소입니다.

작은 Component들이 모여서 하나의 Component를 구성하고 이러한 Component를 모아서 전체페이지를 구성합니다.

이렇게 하나의 Component를 반복적으로 사용함으로써 전체 코드의 양을 줄일 수 있어 개발시간과 유지보수 비용을 줄일 수 있습니다.

 

- 개념적으로는 Javascript의 함수와 비슷합니다. 입력을 받으면 정해진 출력을 합니다.

React는 어떠한 속성(Props)들을 입력받아서 그에 맞는 React element를 return 해주는 것입니다.

* React element: React를 구성하는 가장 작은 블럭들. Javascript 객체 형태로 존재하면 화면에 보이는 것을 기술합니다.

Class  vs  Function

  • app.jsx
// app.jsx

import React from "react";
import "./app.css";
import AppClass from "./components/app_class";
import AppFunc from "./components/app_func";

function App() {
  return (
    <div>
      <AppClass />
      <AppFunc />
    </div>
  );
}

export default App;

 

  • 클래스 컴포넌트(class component)
    : Class는 React에서 제공하는 Component라는 클래스를 extends, 상속해서 만들 수 있다.
    : 함수형 컴포넌트에서 할 수 없었던(React16.8 이전) state관리와 라이프사이클 API를 사용할 수 있었다.
    : Lifecycle methods 제공
// app_class.jsx
import React, { Component } from 'react'

export default class AppClass extends Component {
  render() {
    return (
      <div> class </div>
    )
  }
}
export default AppClass;

 

  • 함수형 컴포넌트(functional component)
    : " render() " 함수가 필요 없다 => 컴포넌트 마운트 속도가 더 빠르고 가독성이 좋다.
    : 원래는 없었지만 리액트 16.8 버전부터 React Hook이 도입되면서
    함수에서도 state관리와(useState) 라이프사이클 API(useEffect)를 심플하게 사용할 수 있게 됐다.
    : Lifecycle에 따른 기능 구현 불가
// app_func.jsx
import React from 'react'

//01번째: 기본 함수형
export default function AppFunc() {
  return (
    <div> Function </div>
  )
}

//02번째: 화살표 함수형
const AppFunc = () => <div> Function </div>;


export default AppFunc;

 

함수형 컴포넌트 사용을 권장하는 이유

1. 함수형 컴포넌트는 가독성이 좋고 간결하다.

=> 코드의 양이 적어지기 때문에 용량이 적어지고 빠르게 랜더링 된다.

2. Hook의 등장 이후로 더욱 사용하기 편해졌다.

3. this를 사용하지 않는 함수형 컴포넌트는 클래스형 컴포넌트의 치명적 단점을 일으키지 않는다.

 

Component 만들기

1. Component 정의하기 

React 컴포넌트의 이름은 항상 대문자로 시작해야 합니다.

export default function Introduce() {
	return (
	<React.Fragment>
		<h1> 컴포넌트 정의하기 </h1>
	</React.Fragment>
	);
}

 

2. Component 내보내기 

" export default "접두사를 사용하면 다른 파일에서 해당 컴포넌트를 가져올 수 있도록 해줍니다.

//첫번째 방법
export default function Introduce() { 
	return (
		// JSX 코드
	);
}
//두번째 방법
function Introduce() {
	return (
		//  JSX 코드
	);
}

export default Introduce;

 

3. Component 불러오기

import문을 사용하여 MyApp 컴포넌트에 Introduce 컴포넌트를 가져와 보기

import Introduce from './Introduce';

export default function MyApp() {
	return (
		// JSX 코드
	);
}

 

4. Component 중첩하기

- 선언한 Introduce 컴포넌트를 MyApp 컴포넌트 안에 중첩해 보기
- 외부 소스로부터 컴포넌트를 사용하기 위해서는, import 구문을 통해 해당 컴포넌트를 프로젝트로 가져와야 합니다. 

- Introduce 컴포넌트는 MyApp 컴포넌트 안에서 렌더링 되기 때문에

  MyApp은 각 Introduce를 자식으로 하는 부모 컴포넌트라고 말할 수 있습니다.

import Introduce from './Introduce';

export default function MyApp() {
	return (
		<div>
			<h1> Welcome </h1>
			<Introduce /> {/* Introduce 컴포넌트 중첩 */}
			<Introduce /> {/* Introduce 컴포넌트 여러번 중첩도 가능 */}
		</div>
	);
}

 

1. 컴포넌트와 HTML 태그를 어떻게 구분하나요?

=> HTML 태그는 소문자이고, 컴포넌트는 대문자로 시작하기 때문에 대소문자로 구분할 수 있습니다.

 

5. Component 추출하기

- Component 가 작아질수록 기능이 명확해지고 props도 단순해집니다

=> 재사용성과 개발속도가 올라갑니다.

- 보통 기능단위로 추출합니다. 


02

Props

부모 컴포넌트가 자식 컴포넌트들에게 마치 함수의 인수를 전달하듯이 값을 전달해주는 방식이 가능합니다.

이때 전달되는 값을 props라고 부릅니다. 사실 props는 'Properties'의 줄임말로 "속성"의 의미를 가집니다.

특징

1. React 내에서 속성(attribute)으로 사용됩니다.

2. 부모 컴포넌트가 자식 컴포넌트로 넘겨주는 주는 정보입니다. (단방향 데이터 흐름)

3. Props는 직접 수정할 수 없습니다. (자식입장에선 읽기 전용인 데이터)

> 수정하려면 부모 컴포넌트에서 데이터를 변경해야 합니다.

4. 같은 Props에 대해서는 항상 같은 결과를 보여줍니다.

사용방법

- Props에 문자열을 전달할 때는 따옴표(" ")(' ')를, 문자열 외의 모든 값을 전달할 때는 중괄호({ })로 값을 감싸야합니다.

 

컴포넌트에 props 전달하기

 

  • 0단계: Profile 컴포넌트는 자식 컴포넌트인 Header/Main/Footer에 어떠한 props도 전달하지 않았습니다.
import React, { Component } from 'react';
import Header from './Header';
import Main from './Main';
import Main from './Footer';

export default function Profile() {
	return (
		<Header />
		<Main />
		<Footer />
	);
}

export default App;

 

  • 1단계: 자식 컴포넌트에 props 전달하기
import React, { Component } from 'react';
import Header from './Header';
import Main from './Main';

export default function Profile() {
	return (
		<Header person={{ name: '김아무개', age: '23' }} developer={true} />
		<Main name= '이아무개' />
		<Footer name= '박아무개' number={9} />
	);
}

export default App;

 

  • 2단계: 자식 컴포넌트 내부에서 props 읽기
function Header({ person, developer }) {
	<>
            <p> 안녕하세요 저의 이름은 {person.name}입니다. </p>
            <p> 나이는 {person.age}살입니다. </p>
            {developer && <p> 저는 현재 개발자로 일하고 있습니다. </p>}
            {/*불리언 타입의 developer값이 true일 경우에만 p의 문구가 출력됩니다.*/}
	</>
};

function Main(props) {
	<>
    	    <h1>제 이름은 {props.name}입니다.</h1>
	</>
};

function Footer(name,number) {
	<>
 	       <h1>제 이름은 {name}이고, 좋아하는 숫자는 {number}입니다.</h1>
	</>
};
  •  Profile은 단지 데이터를 제공하며, Header/Main/Footer컴포넌트는 이 데이터를 받아서 필요한 처리를 하게 됩니다.
  • Header/Main/Footer 컴포넌트의 내부 구현을 변경하더라도, 이 변경이 Profile 컴포넌트에 영향을 미치지 않습니다.
  • 자식 컴포넌트가 props로 받은 정보 중 일부만 필요할 때는 구조 분해 할당을 사용합니다. 

구조 분해 할당

- 구문은 배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 JavaScript 표현식입니다.

  • 배열에 있는 속성을 해체하는 경우
var foo = ["one", "two", "three"];

var [red, yellow, green] = foo;

console.log(red); // "one"
console.log(yellow); // "two"
console.log(green); // "three"

 

  • 객체에 있는 속성을 해체하는 경우
var student = { name: '김코딩', age: 13 };
var { name, age } = student;

console.log(name); // '김코딩'
console.log(age); // 13

 

이와 같은 방식으로 props에서 필요한 값만 구조 분해 할당으로 가져올 수 있습니다.  [참고]

 

  • 3단계: 프로퍼티의 자료형, 타입 정의

프로퍼티의 자료형을 미리 선언할 수 있습니다. 

이를 위해 "prop-types"를 사용하여 각 프로퍼티의 자료형을 정의할 수 있습니다. [참고]

// 프로퍼티 타입 지정
Main.propTypes = {
  name: PropTypes.string
}

 

  • 4단계: 프로퍼티 기본값 설정 및 필수값 설정

- 컴포넌트에 props 기본값을 설정하고 싶은 경우 " defaultProps "를 설정하면 됩니다.

// 프로퍼티 기본값 지정
Main.defaultProps = {
  name: '디폴트'
}


- 기본값을 설정하지 않으면 해당 프로퍼티는 필수 프로퍼티로 선언할 수 있습니다. 

이때 isRequired를 사용하여 필수값으로 설정합니다.

// 프로퍼티 타입 지정 및 필수값 설정
Main.propTypes = {
  name: PropTypes.string.isRequired,
}

 

 

" 마지막으로 중요한 점: Props는 부모에서 자식으로만 전달 가능 "

 

props는 부모 컴포넌트에서 자식 컴포넌트로만 전달이 가능합니다. 
반대로 자식 컴포넌트에서 부모 컴포넌트로 값을 전달하는 것은 React에서 직접적으로 불가능합니다. 
이럴 경우에는 상태 관리(state)나 이벤트를 사용하여 부모와 자식 컴포넌트 간의 상호작용을 처리할 수 있습니다.