Daily Front_Minhhk

[React] props, state 본문

Code개발일지

[React] props, state

Minhhk 2022. 11. 30. 03:01

학습 목표

  • state, props의 개념에 대해서 이해하고, 실제 프로젝트에 바르게 적용할 수 있다.
  • React 함수 컴포넌트(React Function Component)에서 state hook을 이용하여 state를 정의 및 변경할 수 있다.
  • React 컴포넌트(React Component)에 props를 전달할 수 있다.
  • 이벤트 핸들러 함수를 만들고 React에서 이용할 수 있다.
  • 실제 웹 애플리케이션의 컴포넌트를 보고 어떤 데이터가 state이고 props에 적합한지 판단할 수 있다.
  • 실제 웹 애플리케이션 개발 시 적합한 state와 props의 위치를 스스로 정할 수 있다.
  • React의 단방향 데이터 흐름(One-way data flow)에 대해 자신의 언어로 설명할 수 있다.

🔑 Props

Props 는 무엇인가?

  • props 속성의 이름을 임의로 지정해 줄 수 있다.
  • props는 여러 개 지정할 수 있다.
  • 클래스 컴포넌트와 함수형 컴포넌트에서도 사용할 수 있다.
    • ES6 class 문법으로도 컴포넌트를 만들 수 있고, 이를 클래스 컴포넌트라고 한다. 이와 대조해서 함수 문법을 사용하여 만든 컴포넌트를 말 그대로 함수 컴포넌트라고 부른다. Hook이 나오기 전에는 state는 클래스 컴포넌트에만 다룰 수 있었으나, Hook이 나오면서 함수 컴포넌트도 state를 다룰 수 있게 되었다.
  • 컴포넌트의 속성(property)을 의미한다.
    • props는 성별이나 이름처럼 변하지 않는 외부로부터 전달받은 값으로, 웹 애플리케이션에서 해당 컴포넌트가 가진 속성에 해당한다.
    • 속성값은 변하지 않는 불변 변수로 부모 컴포넌트가 주는 속성값을 'props' 형태로 전달 받는다. 또는 구성 요소 자체에서 데이터를 전달하는 데 사용한다.
    • 반대로 state는 컴포넌트 내부에서 변할 수 있는 값이다.
  • 부모 컴포넌트(상위 컴포넌트)로 부터 전달받은 값이다.
    • 리액트 컴포넌트는 자바스크립트 함수와 클래스로, props를 함수의 전달인자(arguments)처럼 전달받아 이를 기반으로 화면에 어떻게 표시되는지를 기술하는 React 엘리먼트를 반환한다. 따라서, 컴포넌트가 최초 렌더링 될 때 화면에 출력하고자 하는 데이터를 담은 초깃값으로 사용할 수 있다.
  • 객체 형태이다.
    • props로 어떤 타입의 값도 넣어 전달할 수 있도록 props는 객체의 형태를 가진다.
  • props는 읽기 전용이다.
    • props는 성별이나 이름처럼 외부로부터 전달받아 변하지 않는 값이다. 그래서 props는 함부로 변경될 수 없는 읽기 전용(read-only) 객체이다. 왜냐하면 함부로 변경되지 않아야 하기 때문이다.
    • 읽기 전용 객체가 아니라면 props를 전달받은 하위 컴포넌트 내에서 props를 직접 수정 시 props를 전달한 상위 컴포넌트의 값에 영향을 미칠 수 있게 된다. 즉, 개발자가 의도하지 않은 side effect가 생기게 되고 이는 리액트의 단방향, 하향식 데이터 흐름 원칙(React is all about one-way data flow down the component hierarchy)에 위배된다.

 

 

props.children

  • props를 전달하는 또 다른 방법으로 여는 태그와 닫는 태그의 사이에 value를 넣어 전달하는 방법이 있습니다. 이 경우 props.children 을 이용하면 해당 value에 접근하여 사용할 수 있습니다
function Parent() {
  return (
    <div className="parent">
        <h1>I'm the parent</h1>
        <Child>I'm the eldest child</Child>
    </div>
  );
};

function Child(props) {
  console.log(props) //{children: "I'm the eldest child"}
  return (

    <div className="child">
        <p>{props.children}</p>

    </div>
  );
};

export default Parent;

 

 

Action item

const App = () => {
  const itemOne = "React를";
  const itemTwo = "배우고 있습니다.";

  return (
    <div className="App">
      {/* Learn 컴포넌트에 itemOne 과 itemTwo 를
      props 로 전달하세요 */}
      <Learn one={itemOne} two={itemTwo}/>
    </div>
  );
};

const Learn = (props) => {
  console.log(props)
  // 전달받은 props 를 아래 <div> tag 사이에 사용하여
  // "React를 배우고 있습니다" 라는 문장이 렌더링되도록 컴포넌트를 완성하세요
  return (
  <>
    <div className="Learn">
      <p>{`${props.one} ${props.two}`}</p>
    </div>

  </>
  )

};

export default App;

 

 


 

 

📚 state

State는 무엇인가?

  • 컴포넌트 내부에서 변할 수 있는 값이다.
  • 리액트에서는 state를 다루는 방법 중 하나로 useState 라는 특별한 함수를 제공한다.
import React, { useState } from "react";

function CheckboxExample() {
  const [isChecked, setIsChecked] = useState(false);

  const handleChecked = (event) => {
    setIsChecked(event.target.checked);
  };
  return (
    <div className="App">
      <input type="checkbox" checked={isChecked} onChange={handleChecked} />
      <span>{isChecked ? "Checked!!" : "Unchecked"}</span>
    </div>
  );
}

export default CheckboxExample;

 

State hook, useState

const [state 저장 변수, state 갱신 함수] = useState(상태 초기 값);

..useState수도 코드

 

 

 

function CheckboxExample() {
  const [isChecked, setIsChecked] = useState(false);
  // const [state 저장 변수, state 갱신 함수] = useState(state 초깃값);

..useState문법 예시

 

 

 

  • 여기서는 isChecked 가 boolean 값을 가지기 때문에 true or false 여부에 따라 다른 결과가 보이도록 삼항연산자를 사용합니다
<span>{isChecked ? "Checked!!" : "Unchecked"}</span>

...JSX에서 삼항연산자 사용 예시

 

state 갱신하기

  • state를 갱신하려면 state 변수를 갱신할 수 있는 함수인 setIsChecked를 호출한다.
  • 이번 예시의 경우, input[type=checkbox] JSX 엘리먼트의 값 변경에 따라서 isChecked가 변경되어야 합니다. 브라우저에서 checked로 값이 변경되었다면, React의 isChecked도 변경되어야한다.
  • input[type=checkbox] 엘리먼트의 값이 변경되면 onChange 이벤트가 발생하고, 이벤트 핸들러 함수가 작동되는 패턴은 DOM을 다뤄보시면서 저번 과제에서 다뤄봤다. 유효성 검사 스프린트에서 input[type=text] 엘리먼트의 값이 변경될 때, 이벤트 핸들러 함수를 작동시키는 패턴을 복습할 수 있다.
  • React 또한 사용자가 체크박스 값을 변경하면 onChange 이벤트가 이벤트 핸들러 함수인 handleChecked를 호출하고, 이 함수가 setIsChecked를 호출하게 된다. setIsChecked가 호출되면 호출된 결과에 따라 isChecked 변수가 갱신되며, React는 새로운 isChecked 변수를 CheckboxExample 컴포넌트에 넘겨 해당 컴포넌트를 다시 렌더링 한다.

state hook 사용 시 주의점

  • 리액트 컴포넌트는 state가 변경되면 새롭게 호출되고, 리렌더링 된다.
  • 리액트 state는 상태 변경 함수 호출로 변경해야 한다. 강제로 변경을 시도하면 안된다. 상태 변경 함수 사용은 리액트와 개발자의 약속이다. 때문에 강제로 변경을 시도하면, 리렌더링이 되지 않는다거나, state가 제대로 변경되지 않는다.

Event handling

HTML에서 이벤트 처리 방식

<button onclick="handleEvent()">Event</button>

React의 이벤트 처리 방식

<button onClick={handleEvent}>Event</button>

onChange

<input> <textarea> <select> 와 같은 폼(Form) 엘리먼트는 사용자의 입력값을 제어하는 데 사용됩니다.

React 에서는 이러한 변경될 수 있는 입력값을 일반적으로 컴포넌트의 state 로 관리하고 업데이트합니다.

onChange 이벤트가 발생하면 e.target.value 를 통해 이벤트 객체에 담겨있는 input 값을 읽어올 수 있습니다.

컴포넌트 return 문 안의 input 태그에 value 와 onChange 를 넣어주었습니다.

@onChange 는 input 의 텍스트가 바뀔 때마다 발생하는 이벤트입니다.

이벤트가 발생하면 handleChange 함수가 작동하며, 이벤트 객체에 담긴 input 값을 setState 를 통해 새로운 state 로 갱신합니다.

function NameForm() {
  const [name, setName] = useState("");

  const handleChange = (e) => {
    setName(e.target.value);
  }

  return (
    <div>
      <input type="text" value={name} onChange={handleChange}></input>
      <h1>{name}</h1>
    </div>)
};

onClick

onClick 이벤트는 말 그대로 사용자가 클릭 이라는 행동을 하였을 때 발생하는 이벤트입니다.

버튼이나 <a> tag 를 통한 링크 이동 등과 같이 주로 사용자의 행동에 따라 애플리케이션이 반응해야 할 때 자주 사용하는 이벤트입니다.

onChange 예시에 버튼을 추가하여 버튼 클릭 시 input tag 에 입력한 이름이 alert을 통해 알림 창이 팝업 되도록 코드를 추가해 보겠습니다.

function NameForm() {
  const [name, setName] = useState("");

  const handleChange = (e) => {
    setName(e.target.value);
  }

  return (
    <div>
      <input type="text" value={name} onChange={handleChange}></input>
      <button onClick={alert(name)}>Button</button>
      <h1>{name}</h1>
    </div>);
};

위와 같이 onClick 이벤트에 alert(name) 함수를 바로 호출하면 컴포넌트가 렌더링 될 때 함수 자체가 아닌 함수 호출의 결과가 onClick 에 적용됩니다.

때문에 버튼을 클릭할 때가 아닌, 컴포넌트가 렌더링 될 때에 alert 이 실행되고 따라서 그 결과인 undefined (함수는 리턴 값이 없을 때 undefined 를 반환합니다.) 가 onClick 에 적용되어 클릭했을 때 아무런 결과도 일어나지 않습니다.

따라서 onClick 이벤트에 함수를 전달할 때는 함수를 호출하는 것이 아니라 아래와 같이

리턴문 안에서 함수를 정의하거나 리턴문 외부에서 함수를 정의 후 이벤트에 함수 자체를 전달해야 합니다.

// 함수 정의하기

return (
  <div>
	...
    <button onClick={() => alert(name)}>Button</button>
	...
  </div>);
};

// 함수 자체를 전달하기

const handleClick = () => {
  alert(name);
};

return (
  <div>
      ...
    <button onClick={handleClick}>Button</button>
      ...
  </div>);
};

Controlled Component

import React, { useState } from "react";

export default function App() {
  const [username, setUsername] = useState("");
  const [msg, setMsg] = useState("");

  return (
    <div className="App">
      <div>{username}</div>
      <input
        type="text"
        value={username}
        onChange={(event) => setUsername(event.target.value)}
        placeholder="여기는 인풋입니다."
        className="tweetForm__input--username"
      ></input>
      <div>{msg}</div>
      {/* TODO : 위 input과 같이 입력에 따라서 msg state가 변할 수 있게 
      아래 textarea를 변경하세요. */}
      <textarea
        placeholder="여기는 텍스트 영역입니다."
        className="tweetForm__input--message"
        onChange={(e) => setMsg(e.target.value)}
        value={msg}
      ></textarea>
    </div>
  );
}

리액트 데이터 흐름

 

<컴포넌트>

상향식(bottom-up)으로 앱을 만듭니다. 이것의 가장 큰 장점은 테스트가 쉽고 확장성이 좋습니다. 그래서 여러분이 기획자나 PM, 또는 UX 디자이너로부터 앱의 디자인을 전달받고 나면, 이를 컴포넌트 계층 구조로 나누는 것이 가장 먼저 해야 할 일입니다.

 

<데이터>

데이터를 전달하는 주체는 부모 컴포넌트가 됩니다. 이는 데이터 흐름이 하향식(top-down) 임을 의미

이 원칙은 매우 중요합니다. 얼마나 중요하냐면, 단방향 데이터 흐름(one-way data flow)이라는 키워드가 React를 대표하는 설명 중 하나일 정도입니다.

 

 

두 개의 자식 컴포넌트가 하나의 상태에 접근하고자 할 때는 두 자식의 공통 부모 컴포넌트에 상태를 위치해야 합니다.

'Code개발일지' 카테고리의 다른 글

REST API  (0) 2022.12.02
HTTP / 네트워크  (0) 2022.11.30
[React] SPA, Router  (0) 2022.11.28
[React] JSX,component  (0) 2022.11.25
[JS] fetch API...sprint  (0) 2022.11.25