6 분 소요


1. props 개요

1.1 props의 개념

props란 부모 컴포넌트가 자식 컴포넌트에게 물려준 데이터이다.

즉, “컴포넌트 간의 정보 교류 방법”을 말한다.


1.2 props의 특징

props는 중요한 특징이 있다.⭐

  1. props는 반드시 위에서 아래 방향으로 흐른다. 즉, [부모] → [자식] 방향으로만 흐른다(단방향).
  2. props는 반드시 읽기 전용으로 취급하며, 변경하지 않는다.



2. props로 값 전달하기

아래 코드에서 Child 컴포넌트에서 Mother의 이름을 어떻게 알 수 있도록 할까?

// src/App.js

import React from "react";

function Child() {
  return <div>자식입니다.</div>;
}

function Mother() {
  const name = "김춘자";
  return <Child />;
}

function GrandFather() {
  return <Mother />;
}

function App() {
  return <GrandFather />;
}

export default App;


2.1 전달하기 - [주체 : 부모]

컴포넌트 간의 정보를 교류할 때 Props를 사용한다.

만약 Mother 컴포넌트가 가지고 있는 정보(값)를 Child에게 주고 싶을 때는 아래 코드와 같이 작성한다.

function Mother() {
  const name = "김춘자";
  return <Child motherName={name} />;
}

즉, motherName이라는 이름으로 name 값을 Child 컴포넌트에게 전달해준 것이다.

이 과정을 “Props 로 정보를 전달했다” 라고 표현한다.


2.2 받기 - [주체 : 자식]

Mother가 전달해준 motherNameChild가 받게 하려면 컴포넌트의 인자에서 props의 값을 받으면 된다.

function Child(props) {
  return <div>자식입니다.</div>;
}

Mother가 보내준 정보는 객체 형태이다.

② 즉, props란 결국 부모 컴포넌트가 자식에게 넘겨준 데이터들의 묶음인 것이다.

③ 이렇게 리액트에서는 Props를 통해 부모 컴포넌트로부터 자식 컴포넌트에 데이터를 넘겨줄 수 있다.


2.3 props로 받은 값을 화면에 렌더링 하기

Mother로부터 전달받은 motherName을 화면에 렌더링해보자

// src/App.js

import React from "react";

function Child(props) {
  // console.log(props); // 객체형태로 값 전달받음
  return <div>{props.motherName}의 자식입니다.</div>; // 따라서 props. 사용
}

function Mother() {
  const name = "김춘자";
  return <Child motherName={name} />; // 💡"props로 name을 전달했다."
}

function GrandFather() {
  return <Mother />;
}

function App() {
  return <GrandFather />; // "김춘자의 자식입니다."
}

export default App;

① props는 object literal 형태이기 때문에 {props.motherName} 로 꺼내서 사용할 수 있다.

② object literal의 key가 motherName 인 이유는 Child로 보내줄 때 motherName={name} 으로 보내주었기 때문이다.

③ object literal 란 {key: “value”} 데이터 형태를 의미한다.


2.4 props 사용해보기

할아버지의 이름을 Child에게 전달해보자!

GrandFather 컴포넌트에서 GrandFatherName을 만들어서 화면에 렌더링하면 된다.

// src/App.js

import React, { useState } from "react";
import "./App.css"; // App.css 파일을 import 해줘야 한다.

function Child(props) {
  return <div>{props.grandFather}의 손자입니다.</div>;
}

function Mother(props) {
  return <Child grandFather={props.grandFather} />;
}
function GrandFather() {
  const name = "산타할아버지";
  return <Mother grandFather={name} />;
}
const App = () => {
  return <GrandFather />; // "산타 할아버지의 손자입니다."
};

export default App;


2.5 prop drilling

컴포넌트 계층 구조에서 데이터가 여러 단계를 거쳐 하위 컴포넌트로 전달되는 현상을 말한다.

데이터를 받지 않아도 되는데도 데이터를 전달해주는 용도로만 사용되는 것이 특징이다.

예를들어 [부모] → [자식] → [그 자식] → [그 자식의 자식]과 같을 때, “부모” 컴포넌트에서부터 차례대로 “자식”, “그 자식”까지 데이터를 전달해야 한다.

이때, 중간에 위치한 “자식” 컴포넌트는 실제로 필요하지 않은 데이터를 받아서 다시 전달해야 하는데, 이런 과정이 prop drilling인 것이다.


아래의 코드처럼 prop drilling 현상을 피해야한다.
이를 해결하기 위해 ‘Redux’와 같은 데이터 상태관리 툴을 배워야 하는 것이다.

export default function App() {
  return (
    <div className="App">
      <FirstComponent content="Who needs me?" />
    </div>
  );
}

function FirstComponent({ content }) {
  return (
    <div>
      <h3>I am the first component</h3>;
      <SecondComponent content={content} />|
    </div>
  );
}

function SecondComponent({ content }) {
  return (
    <div>
      <h3>I am the second component</h3>;
      <ThirdComponent content={content} />
    </div>
  );
}

function ThirdComponent({ content }) {
  return (
    <div>
      <h3>I am the third component</h3>;
      <ComponentNeedingProps content={content} />
    </div>
  );
}

function ComponentNeedingProps({ content }) {
  return <h3>{content}</h3>;
}



3. props children

3.1 props children 사용해보기

자식 컴포넌트로 정보를 전달하는 또 다른 방법이다.

먼저 목차 2에서 실습한 것처럼 props children을 사용하지 않고 상위컴포넌트에서 하위컴포넌트로 정보를 전달해보자!

  • User 컴포넌트에 아무런 프로퍼티를 전달하지 않고, 하위컴포넌트를 출력해보자

    import logo from "./logo.svg";
    import "./App.css";
    
    function App() {
      return <User />;
    }
    function User() {
      return <div>하위컴포넌트</div>;
    }
    
    export default App;
    


  • 이제, props를 사용하여 상위컴포넌트에서 정보를 전달해보자

    import logo from "./logo.svg";
    import "./App.css";
    
    function App() {
      const name = "상위 컴포넌트 name";
      return <User name={name} />;
    }
    function User(props) {
      return <div>{props.name}</div>;
    }
    
    export default App;
    


  • 그렇다면 아래 코드를 보자

    import logo from "./logo.svg";
    import "./App.css";
    
    function App() {
      return <User>안녕하세요</User>;
    }
    
    function User(props) {
      return <div>{props.children}</div>;
    }
    
    export default App;
    

    ① App 컴포넌트가 User 컴포넌트를 자식으로 품고 있다.

    <User hello='안녕하세요'> 이렇게 props를 보내던 방식이 아닌 <User>안녕하세요</User> 이렇게 정보를 보내는 것이 children props를 보내는 방식이다.

    ③ 부모 컴포넌트에서 정보를 받기 위해 {props.children}와 같이 작성해주면 된다.


3.2 props children의 용도

Layout 컴포넌트를 만들 때 자주 사용한다.

아래 코드를 보면 Layout 컴포넌트 안에는 header 라는 컴포넌트가 있고, header 아래에 {props.children} 를 통해서 props를 받아 렌더링 하고 있다.

즉, Layout 컴포넌트가 쓰여지는 모든 곳에서 <Layout>…</Layout> 안에 있는 정보를 받아서 가져올 수 있는 것이다.

// src/Layout.js 생성
import React from "react";

function Layout(props) {
  return (
    <>
      <header style={{ margin: "10px", border: "1px solid red" }}>
        항상 출력되는 머릿글
      </header>
      {props.children}
    </>
  );
}

export default Layout;


// scr/App.js
import "./App.css";
import Layout from "./Layout";

function App() {
  return (
    <Layout>
      <div>App 컴포넌트에서 보낸 </div>
    </Layout>
  );
}

export default App;

App 컴포넌트에서는 Layout 컴포넌트를 가져와서 사용한다.

Layout 컴포넌트는 자식으로 <div>App 컴포넌트에서 보낸 값</div>을 받아 렌더링한다.

이를 통해 App 컴포넌트에서는 Layout 컴포넌트를 활용하여 공통된 레이아웃을 사용할 수 있는 것이다.




4. props 추출

4.1 구조분해 할당과 props📌

구조분해할당 》포스팅을 먼저 보고 와주세요.

지금까지 자식 컴포넌트에서 props를 받을 때 아래처럼 작성하였다.

function Todo(props) {
  return <div>{props.todo}</div>;
}


​ 문제는 없지만 todo 라는 props를 사용하는 모든 곳에서 props. 를 붙여줘야 했다.

JS의 구조 분해 할당을 이용하면 조금 더 짧게 쓸 수 있다.

props는 object literal 형태의 데이터이므로 아래처럼 구조 분해 할당을 통해 props의 내부값을 추출할 수 있는 것이다.

// src/App.jsx
import "./App.css";
import Child from "./layouts/Child";

function App() {
  const name = "코리";
  const age = "8";
  return <Child name={name} age={age} />;
}

export default App;
// scr/Child.jsx
import React from "react";

// 구조분해할당 x
// function Child(props) {
//   return (
//     <div>
//       <div>이름: {props.name}</div>
//       <div>나이: {props.age}</div>
//     </div>
//   );
// }

function Child({ name, age }) {
  return (
    <div>
      <div>이름: {name}</div>
      <div>나이: {age}</div>
    </div>
  );
}

export default Child;

구조분해할당을 사용하면 Child 컴포넌트에서 어떠한 props가 쓰이고 있는지를 직관적으로 알 수 있다.

즉, 구조 분해 할당을 이용해서 props를 사용하는 것이 효율적이다!


4.2 defaultProps

defaultProps란, 부모 컴포넌트에서 props를 보내주지 않아도 설정될 초기 값을 말한다.

컴포넌트를 만들고 자식 컴포넌트에서 props를 받다보면, 자주 받거나 또는 무조건 받아야 하는 props들이 있다.

// src/App.js
import React from "react";
import Child from "Child";

function App() {
  const name = "sieun";

  return <Child age={22}>이름</Child>;
}

export default App;
// Child.jsx
import React from "react";

function Child({ age, name, Children }) {
  console.log(age);
  console.log(name);
  console.log(Children);
  return <div>Child</div>;
}

export default Child;

Child 컴포넌트에선 age의 props 정보를 받길 원하고 있지만, App 컴포넌트에선 age의 props의 정보를 보내지 않은 상태이다.

따라서 자식 컴포넌트 입장에서는 age가 무엇인지 알 수 없기 때문에 아래와 같이 undefined가 출력되는 것을 알 수 있다.


이를 해결하기 위해 부모 컴포넌트에서 props를 받기전까지 임시로 사용 할 수 있는 propsChild 컴포넌트에서 설정 할 수 있다.


default props 지정하기

// Child.jsx
import React from "react";

function Child({ age, name, Children }) {
  console.log(age);
  console.log(name);
  console.log(Children);
  return <div>Child</div>;
}

Child.defaultProps = {
  age: "기본 나이",
};

export default Child;

이렇게 defaultProps를 설정하면, 부모 컴포넌트로부터 아직 props 값을 받지 못했더라고 임시로 props의 값을 채울 수 있다.

그리고 부모 컴포넌트로부터 props가 오게되면 defaultProps 값은 진짜 props 값으로 변경된다.


4.3 Default Argument

defaultProps를 설정하는 또 다른 방법 이다. 마치 함수의 default argument를 설정하는 것과 같다.

매개변수가 지정되지 않았으면 자동으로 지정해줄 값을 정하라는 의미인 것이다.

// b를 1로 세팅하여 defaultProps를 설정
function multiply(a, b = 1) {
  return a * b;
}

console.log(multiply(5, 2));
// Expected output: 10

console.log(multiply(5));
// Expected output: 5


카테고리:

업데이트:

댓글남기기