React Props&State

유슬기·2023년 1월 27일
0

프론트엔드

목록 보기
30/64
post-thumbnail

Props

props의 특징

  • 컴포넌트의 속성(property)을 의미
  • 외부(부모 또는 상위 컴포넌트)로부터 전달받은 값
  • React 컴포넌트는 JavaScript 함수와 클래스로, props를 함수의 전달인자(arguments)처럼 전달받아 이를 기반으로 화면에 어떻게 표시되는지를 기술하는 React 엘리먼트를 반환하기 때문에 컴포넌트가 최초 렌더링 될 때 화면에 출력하고자 하는 데이터를 담은 초깃값으로 사용할 수 있음
  • props로 어떤 타입의 값도 넣어 전달할 수 있도록 객체 형태를 가짐
  • 이름, 성별처럼 변화가 없는 값으로, 함부로 변경될 수 없는 읽기 전용(read-only) 객체

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

  • 클래스 컴포넌트뿐만 아니라 함수형 컴포넌트에서도 사용할 수 있음

    ES6 class 문법으로도 컴포넌트를 만들 수 있고, 이를 클래스 컴포넌트라고 합니다. 이와 대조해서 함수 문법을 사용하여 만든 컴포넌트를 말 그대로 함수 컴포넌트라고 부릅니다. Hook이 나오기 전에는 state는 클래스 컴포넌트에만 다룰 수 있었으나, Hook이 나오면서 함수 컴포넌트도 state를 다룰 수 있게 되었습니다.

props의 사용법

  1. 하위 컴포넌트에 전달하고자 하는 값(data)과 속성을 정의
  2. props를 이용하여 정의된 값과 속성을 전달
  3. 전달받은 props를 렌더링
// 0. 위 단계에 맞추어 props를 사용하기 위해 우선 <Parent> 와 <Child> 라는 컴포넌트를 선언하고, 
// <Parent> 컴포넌트 안에 <Child> 컴포넌트를 작성

function Parent() {
  return (
    <div className="parent">
      <h1>I'm the parent</h1>
      <Child />
    </div>
  );
};

function Child() {
  return (
    <div className="child"></div>
  );
};
// 1. 하위 컴포넌트에 전달하고자 하는 값과 속성을 정의
// 구문: 부모(상위)컴포넌트 내 코드에 작성 <Child attribute={value} />

function Parent() {
  return (
    <div className="parent">
      <h1>I'm the parent</h1>
			{/* text 속성 선언 및 문자열 값을 할당하여 Child 컴포넌트에 전달 */}
      <Child text={"I'm the eldest child"} />
    </div>
  );
};

// 2. 상위 컴포넌트에서 전달한 문자열을 하위 컴포넌트에서 받아오기
// 함수에 인자를 전달하듯 하위 컴포넌트에 props를 전달

function Child(props) {
  return (
    <div className="child"></div>
  );
};
// 3. 전달받은 props를 렌더링
// props는 객체이기 때문에 { 키: 값 } 형태, 사용할 때도 dot notation으로 접근할 수 있음

function Child(props) {
  return (
    <div className="child">
      <p>{props.text}</p> {/* 중괄호로 작성 */}
    </div>
  );
};

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) {
  return (
    <div className="child">
        <p>{props.children}</p>
    </div>
  );
};

State

state의 특징

  • 컴포넌트의 사용 중 컴포넌트 내부에서 변할 수 있는 값(변화가 필요한 데이터)
  • 나이, 현재 사는 곳, 취업 여부, 결혼/연애 여부처럼 변화하는 값
  • state가 변경되면 컴포넌트가 갱신되면서 사용자가 해당 내용을 확인할 수 있음
  • state는 하위 컴포넌트에서도 존재할 수 있음
  • 함수 컴포넌트에서도 사용 가능

    React 16.8 버전에 Hook이 추가되면서 클래스 컴포넌트를 작성하지 않아도 state를 사용할 수 있게 되었습니다.

State hook, useState

useState 사용법

  1. useState를 이용하기 위해 React에서 import 키워드로 불러오기

    import { useState } from "react";
  2. useState를 컴포넌트 안에서 호출

    • useState 를 호출한다는 것은 "state" 라는 변수를 선언하는 것과 같으며, 이 변수의 이름은 아무 이름으로 지어도 된다. 일반적인 변수는 함수가 끝날 때 사라지지만, state 변수는 React에 의해 함수가 끝나도 사라지지 않는다.
    // 기본 문법
    const [state 저장 변수, state 갱신 함수] = useState(상태 초기 값);
    function CheckboxExample() {
    // 새로운 state 변수를 선언, 구조 분해 할당 (예시의 변수명: isChecked)
      const [isChecked, setIsChecked] = useState(false);
    }
    
    // 위 코드를 풀어쓰면 아래와 같음
    function CheckboxExample() {
    	const stateHookArray = useState(false);
      const isChecked = stateHookArray[0];
      const setIsChecked = stateHookArray[1];
    }
    • isChecked : state를 저장하는 변수
    • setIsChecked : state isChecked 를 변경하는 setState함수
    • useState : state hook
    • false : state 초깃값
  3. state 변수에 저장된 값을 사용하려면 JSX 엘리먼트 안에 직접 불러서 사용

    // 예시에서 isChecked가 boolean 값을 가지므로 참/거짓 여부에 따라 다른 결과가 보이도록 삼항 연산자 사용
    return (
      <div className="App">
        <input type="checkbox" checked={isChecked} onChange={handleChecked} />
        <span>{isChecked ? "Checked!!" : "Unchecked"}</span>
      </div>
    );

state 갱신하기

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>
  );
}
  • state를 갱신하려면 state 변수를 갱신할 수 있는 함수인 setIsChecked 를 호출
  • 위 예시의 경우, input[type=checkbox] JSX 엘리먼트의 값 변경에 따라서 isChecked 가 변경되어야 하므로, 브라우저에서 checked로 값이 변경되었다면, React의 isChecked 도 변경되어야함
    1. input[type=checkbox] 엘리먼트의 값(체크박스 값)이 변경되면 onChange 이벤트가 발생
    2. 이벤트 핸들러 함수인 handleChecked 를 호출하고, 이 함수가 setIsChecked 를 호출
    3. setIsChecked 가 호출되면 호출된 결과에 따라 isChecked 변수가 갱신되며, React는 새로운 isChecked 변수를 CheckboxExample 컴포넌트에 넘겨 해당 컴포넌트를 다시 렌더링

state hook 사용 시 주의점

  • React 컴포넌트는 state가 변경되면 새롭게 호출되고, 리렌더링 됨
  • React state는 상태 변경 함수 호출로 변경해야 함
    • 강제로 변경을 시도하면, 리렌더링이 되지 않는다거나, state가 제대로 변경되지 않음
    • 예시: state.push(1);, state[1] = 2;, state = 'wrong state';

이벤트 핸들링

React의 이벤트 처리(이벤트 핸들링; Event handling) 방식은 DOM의 이벤트 처리 방식과 유사하나, 몇 가지 문법 차이가 있음

  • React 에서 이벤트는 소문자 대신 카멜 케이스(camelCase) 를 사용
  • JSX를 사용하여 문자열이 아닌 함수로 이벤트 처리 함수(이벤트 핸들러; Event handler)를 전달
// HTML 이벤트 처리 방식
<button onclick="handleEvent()">Event</button>

// React 이벤트 처리 방식
<button onClick={handleEvent}>Event</button>

자주 사용하는 이벤트 핸들링

  1. onChange

    • <input>, <textarea>, <select> 와 같은 폼(Form) 엘리먼트는 사용자의 입력값을 제어하는 데 사용되며, React 에서는 이러한 변경될 수 있는 입력값을 일반적으로 컴포넌트의 state 로 관리하고 업데이트 함
    • onChangeinput 의 텍스트가 바뀔 때마다 발생하는 이벤트로, onChange 이벤트가 발생하면 handleChange 함수가 작동하며, 이벤트 객체에 담긴 input 값을 setState(여기선 setName) 를 통해 새로운 state 로 갱신함
    • e.target.value 를 통해 이벤트 객체에 담겨있는 input 값을 읽어올 수 있음
    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>
      )
    };
    • name : state를 저장하는 변수
    • setName : state name 을 변경하는 setState함수
    • useState : state hook
    • “” : state 초깃값
  2. onClick

    • onClick 이벤트는 사용자가 ‘클릭’이라는 행동을 하였을 때 발생하는 이벤트

    • 버튼이나 <a> tag 를 통한 링크 이동 등과 같이 주로 사용자의 행동에 따라 애플리케이션이 반응해야 할 때 자주 사용함

    • onClick 이벤트에 함수를 전달할 때는 함수를 호출하는 것이 아니라 아래와 같이 리턴문 안에서 함수를 정의하거나 리턴문 외부에서 함수를 정의 후 이벤트에 함수 자체를 전달해야 함

      // 함수 정의하기
      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>
      
      // 함수 자체를 전달하기
      function NameForm() {
        const [name, setName] = useState("");
      
        const handleChange = (e) => {
          setName(e.target.value);
        }
      
      	const handleClick = () => {
      	  alert(name);
      	};
      	
        return (
          <div>
            <input type="text" value={name} onChange={handleChange}></input>
            <button onClick={handleClick}>Button</button>
            <h1>{name}</h1>
          </div>
      	);
      };
      // 잘못된 사용 예시
      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 반환*/
      
      // onClick(undefined) → 아무런 결과도 일어나지 않음

이벤트 핸들러 실습

  1. <select>

    select tag 는 사용자가 drop down 목록을 열어 그중 한 가지 옵션을 선택하면, 선택된 옵션이 state 변수에 갱신됩니다. useState 가 어떠한 상태를 갱신하도록 설정되어 있는지 확인한 뒤, 주석에 따라 select tag 가 정상적으로 작동하도록 코드를 완성하세요.

    function SelectExample() {
      const [choice, setChoice] = useState("apple");
    
      const fruits = ["apple", "orange", "pineapple", "strawberry", "grape"];
      const options = fruits.map((fruit) => {
        return <option value={fruit}>{fruit}</option>;
      });
      console.log(choice);
      const handleFruit = (event) => {
        //TODO : select tag 가 정상적으로 작동하도록 코드를 완성하세요.
    		setChoice(event.target.value)
      };
    
      return (
        <div className="App">
          <select onChange={handleFruit}>{options}</select>
          <h3>You choose "{choice}"</h3>
        </div>
      );
    }
  2. Pop up

    Pop up 역시 Pop up 의 open 과 close 를 state 를 통해 관리할 수 있습니다. 이 예제 또한 useState 를 확인하여 버튼 클릭에 따라 Pop up 이 open/close 되도록 코드를 완성하세요.

    function App() {
      const [showPopup, setShowPopup] = useState(false);
    
      const togglePopup = () => {
        // Pop up 의 open/close 상태에 따라 현재 state 가 업데이트 되도록 함수를 완성하세요.
    
    		if (!showPopup) { // showPopup이 false이면,
          setShowPopup(true); // state를 true로 업데이트
        } else {
          setShowPopup(false); // 아니면(true이면) false로 업데이트
        }
      };
    
      return (
        <div className="App">
          <h1>Fix me to open Pop Up</h1>
          {/* 버튼을 클릭했을 때 Pop up 의 open/close 가 작동하도록
              button tag를 완성하세요. */}
          <button className="open" onClick={togglePopup}>Open me</button>
          {showPopup ? (
            <div className="popup">
              <div className="popup_inner">
                <h2>Success!</h2>
                <button className="close" onClick={togglePopup}>
                  Close me
                </button>
              </div>
            </div>
          ) : null}
        </div>
      );
    }

React Controlled Component

React가 state를 통제할 수 있는 컴포넌트이다.

How?

input에 값 입력 시, state도 그때그때 바뀌고(onChange), 변경된 state와 input의 value가 같게 작성하면 된다.

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, textarea에 입력된 내용이 바뀌면 
      이벤트 핸들러와 setState 함수를 통해 state를 업데이트 해 주고, 
      value에 state 값을 넣어준다. */}
      <input
        type="text"    
        onChange={(event) => setUsername(event.target.value)}       
        value={username}
        placeholder="여기는 인풋입니다."
        className="tweetForm__input--username"
      ></input>
      <div>{msg}</div>
      <textarea
        placeholder="여기는 텍스트 영역입니다."
        className="tweetForm__input--message"
        onChange={(event) => setMsg(event.target.value)}
        value={msg}
      ></textarea>
    </div>
  );
}
profile
아무것도 모르는 코린이

0개의 댓글