[React] 기초 - State & Props

LEE JI YOUNG·2021년 9월 27일

React

목록 보기
6/19
  • State : 변할 수 있는 값. 컴포넌트 사용 중 컴포넌트 내부에서 변할 수 있는 값. 컴포넌트 안에서만 지지고 볶고 변화되는 값.

    • 컴포넌트의 State 예시
  • Props : 외부로부터 전달받은 값. 인자와 같이 위로부터 넘겨 받을 수 있는 것.




Props

  • 컴포넌트의 속성(property)을 의미. 변하지 않는 외부로부터 전달받은 값으로, 웹 어플리케이션에서 해당 컴포넌트가 가진 속성에 해당

props의 특징

  • 컴포넌트의 속성(property)

  • 부모 컴포넌트(상위 컴포넌트)로부터 전달받은 값
    : React 컴포넌트는 JavaScript 함수와 클래스로, props를 함수의 전달인자(arguments)처럼 전달받아 이를 기반으로 화면에 어떻게 표시되는지를 기술하는 React 엘리먼트를 반환. 컴포넌트가 최초 렌더링될 때에 화면에 출력하고자 하는 데이터를 담은 초기값으로 사용 가능.

    • <Child attribute={value} />
    • 함수에 인자를 전달하듯이 React 컴포넌트에 props 를 전달하면 되고, 이 props 가 필요한 모든 데이터를 가지고 오게 된다.
  • 객체{ attribute : value } 형태
    : props로 어떤 타입의 값도 넣어 전달할 수 있도록 props는 객체의 형태를 가진다. props 의 value 또한 dot notation 으로 접근 가능.

  • props는 읽기 전용
    : props는 성별이나 이름처럼 외부로부터 전달받아 변하지 않는 값. 그래서 props는 함부로 변경될 수 없는 읽기 전용(read-only) 객체가 되었다. 함부로 변경되지 않아야 하기 때문.

    • 읽기 전용 객체가 아니라면 props를 전달받은 하위 컴포넌트 내에서 props 를 직접 수정 시 props를 전달한 상위 컴포넌트의 값에 영향을 미치게 되어, 개발자가 의도하지 않은 side effect가 생기게 됨. 이는 React의 단방향, 하향식 데이터 흐름 원칙(React is all about one-way data flow down the component hierarchy)에 위배됨.

props 사용 방법 3단계 순서

1) 하위 컴포넌트에 전달하고자 하는 값(data)과 속성을 정의한다.
<Child text={"I'm the eldest child"} />
2) props를 이용하여 정의된 값과 속성을 전달한다.
function Child(props){}
3) 전달받은 props를 렌더링한다.
{props.text}

//  <Child> 컴포넌트에서 props.text렌더링 예시

// 상위 컴포넌트
function Parent() {
  return (
    <div className="parent">
      <h1>I'm the parent</h1>
     //하위 컴포넌트의 Props 
      <Child text={"I'm the eldest child"} />
    </div>
  );
};
// 하위 컴포넌트 . props를 써서 전달받음.
function Child(props) {
  return (
    <div className="child">
      // props 를 렌더링하려면 JSX 안에 직접 불러서 사용 
      <p>{props.text}</p>
    </div>
  );
};

import "./styles.css";

function Parent() {
  return (
    <div className="parent">
      <h1>I'm the parent</h1>
      <Child text={"I'm the eldest child"} />
      {/* Child 컴포넌트에 또 다른 문자열을 props 로 전달해 보세요 */}
      <Child text={"I'm the second child"} />
    </div>
  );
}

function Child(props) {
  // console 을 열어 props 의 형태를 직접 확인하세요.
  console.log("props : ", props);
  return (
    <div className="child">
      <p>{props.text}</p>
    </div>
  );
}

export default Parent;

props.children

1) <Child>I'm the eldest child</Child> props 를 전달하는 또 다른 방법으로 여는 태그와 닫는 태그의 사이에 value 를 넣어 전달한다..
2) props.children 을 이용하여 해당 value 에 접근하여 사용한다.

import "./styles.css";

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

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

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

export default App;




State

  • 애플리케이션의 "상태"
  • state는 Toggle Switch, Counter, 체크박스 처럼 컴포넌트 내부에서 변할 수 있는 값
// 1 ) useState 불러오기
import React, { useState } from "react";
import "./styles.css";


function CheckboxExample() {

  // 2 ) 새로운 state 변수를 선언하고, 여기서는 이것을 isChecked 라 부르겠다.
  const [isChecked, setIsChecked] = useState(false);
  
  const handleChecked = (event) => {
    // ★ state 갱신하려면 state 변수를 갱신할 수 있는 함수인 setIsChecked를 호출.
    setIsChecked(event.target.checked);
  };
  
  
  return (
    <div className="App">
    
// 4) input[type=checkbox] JSX 엘리먼트의 값 변경에 따라서 isChecked가 변경.
// 5) input[type=checkbox] 엘리먼트의 값이 변경되면 onChange 이벤트가 발생.
      <input type="checkbox" checked={isChecked} onChange={handleChecked} />
    
// 3)  state 변수에 저장된 값을 사용하려면 JSX 엘리먼트 안에 직접 불러서 사용
      <span>{isChecked ? "Checked!!" : "Unchecked"}</span>

    </div>
  );
}

export default CheckboxExample;

useState 사용법 (State hook, useState)

: React에서는 state 를 다루는 방법 중 하나로 useState 라는 특별한 함수를 제공

1) useState 를 이용하기 위해 React로부터 useState 를 불러오기
import { useState } from "react";

2) useState 를 컴포넌트 안에서 호출하기 = state 라는 변수를 선언한다.
const [state 저장 변수, state 갱신 함수] = useState(상태 초기 값);

  • 변수의 이름은 아무거나 상관없다.
  • 일반적인 변수는 함수가 끝날 때 사라짐, 그러나 state 변수는 React에 의해 함수가 끝나도 사라지지 않는다.
  • 문법적으로 보면 아래 예시의 isChecked, setIsCheckeduseState 의 리턴값을 구조 분해 할당한 변수이다.
// useState 구조 분해 할당 예시

function CheckboxExample() {
  // 1번 코드를 풀어쓰면
  const [isChecked, setIsChecked] = useState(false); // 1번

  //...

  // 2번 코드와 같습니다.
  const stateHookArray = useState(false); 
  // useState 를 호출하면 배열 반환.
  // useState 의 인자로 넘겨주는 값은 state의 초기값 = (괄호안의 값)
  const isChecked = stateHookArray[0]; //  배열의 0번째 요소는 현재 state 변수
  const setIsChecked = stateHookArray[1]; // 1번째 요소는 이 변수를 갱신할 수 있는 함수
}
  • isChecked : state를 저장하는 변수
  • setIsChecked : state isChecked 를 변경하는 함수
  • useState : state hook
  • false : state 초기값

3) state 변수에 저장된 값을 사용하려면 JSX 엘리먼트 안에 직접 불러서 사용
<span>{isChecked ? "Checked!!" : "Unchecked"}</span>
: isChecked 가 boolean 값을 가지기 때문에 true or false 여부에 따라 다른 결과가 보이도록 삼항연산자를 사용.


state 갱신하기

: React 컴포넌트는 state가 갱신되면 새롭게 호출되고, 리렌더링 된다. state 갱신하려면 state 변수를 갱신할 수 있는 함수인 setIsChecked를 호출.

4) input[type=checkbox] JSX 엘리먼트의 값 변경에 따라서 isChecked가 변경.
: 브라우저에서 checked로 값이 변경되었다면, React의 isChecked 도 변경.

5) input[type=checkbox] 엘리먼트의 값이 변경되면 onChange 이벤트가 발생.
: 사용자가 체크박스 값을 변경하면 onChange 이벤트가 이벤트 핸들러 함수인 handleChecked 를 호출
-> 이 함수가 setIsChecked 를 호출
-> setIsChecked 가 호출되면 호출된 결과에 따라 isChecked 변수가 갱신
-> React는 새로운 isChecked 변수를 CheckboxExample 컴포넌트에 넘겨 해당 컴포넌트를 다시 렌더링.


useState 주의 할 점

: React state는 상태 변경 함수 호출로 변경해야 함. 강제로 변경을 시도하면 리렌더링이 되지 않는다거나, state가 제대로 변경되지 않는다

  • 예시 : state.push(1);, state[1] = 2;, state = 'wrong state';
    • 강제로 상태를 변경하려고 시도하는 경우

이벤트 처리 Hands-on

  • React의 이벤트 처리(이벤트 핸들링; Event handling) 방식은 DOM의 이벤트 처리 방식과 유사하나, 문법 차이 있음.
    • React 에서 이벤트는 소문자 대신 카멜 케이스(camelCase) 를 사용
    • JSX를 사용하여 문자열이 아닌 함수로 이벤트 처리 함수(이벤트 핸들러; Event handler)를 전달
// 예를 들어 
// HTML에서 이벤트 처리 방식
<button onclick="handleEvent()">Event</button>
//React의 이벤트 처리 방식은 아래와 같습니다. 
<button onClick={handleEvent}>Event</button>

onChange

  • <input> <textarea> <select> 와 같은 폼(Form) 엘리먼트는 사용자의 입력값을 제어하는데 사용. React 에서는 변경될 수 있는 입력값을 일반적으로 컴포넌트의 state 로 관리하고 업데이트.
function NameForm() {
  const [name, setName] = useState("");
  
  
// onChange 이벤트가 발생 -> handleChange 함수가 작동 -> 
  // e.target.value 를 통해 이벤트 객체에 담겨있는 input 값을 읽어온다. 
  //이벤트 객체에 담긴 input 값을 setState 를 통해 새로운 state 로 갱신
  const handleChange = (e) => {
    setName(e.target.value);
  }

  return (
    <div>
     // onChange 는 input 의 텍스트가 바뀔 때 마다 발생하는 이벤트. 
       // 이벤트가 발생하면 handleChange 함수가 작동.
      <input type="text" value={name} onChange={handleChange}></input>
      <h1>{name}</h1>
    </div>
  )
};

onClick

  • Click 이벤트(<button>이나 <a>를 통한 링크 이동 등과 같이 주로 사용자의 행동에 따라 애플리케이션이 반응해야 할 때 자주 사용하는 이벤트)는 말 그대로 사용자가 클릭이라는 행동을 하였을 때 발생하는 이벤트
function NameForm() {
  const [name, setName] = useState("");
// 방법 3) 리턴문 외부에서 함수를 정의 후 이벤트에 함수 자체를 전달
  const handleChange = (e) => {
    setName(e.target.value);
  }

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

방법 1 )<button onClick={alert(name)}>Button</button> (X)
방법 2 ) <button onClick={() => alert(name)}>Button</button> (O)
: 방법 1 ) 처럼 onClick 이벤트에 alert(name) 함수를 바로 호출하면 컴포넌트가 렌더링될 때 함수 자체가 아닌 함수 호출의 결과가 onClick 에 적용. 때문에 버튼을 클릭할 때가 아닌, 컴포넌트가 렌더링될 때에 alert 이 실행되고 따라서 그 결과인 undefined (함수는 리턴값이 없을 때 undefined 를 반환.). onClick 에 적용되어 클릭했을 때 아무런 결과도 일어나지 않는다.
따라서 onClick 이벤트에 함수를 전달할 때는 함수를 호출하는 것이 아니라 방법 2) 와 같이 리턴문 안에서 함수를 정의하거나 방법 3) 리턴문 외부에서 함수를 정의 후 이벤트에 함수 자체를 전달해야 합니다.

  • 방법 2, 방법 3 )모두 arrow function 을 사용하여 함수를 정의하여야 해당 컴포넌트가 가진 state에 함수들이 접근할 수 있다.
profile
프론트엔드 개발자

0개의 댓글