[React] state & props

KoEunseo·2022년 8월 2일
0

코드스테이츠

목록 보기
10/45

state : 내부에서 변화하는 값

변할 수 있는 값
컴포넌트를 사용하는동안 컴포넌트 내부에서 변할 수 있는 값

props : 외부에서 전달받은 값

컴포넌트의 속성을 의미한다.
부모 컴포넌트로부터 전달받은 값을 의미한다.
최초 렌더링 될 때 화면에 출력하고자 하는 데이터를 담은 초기값으로 사용.
객체형태이다.
읽기 전용이다. 함부로 변경되지 않아야한다.
하위 컴포넌트 내에서 값이 수정되면 상위 컴포넌트에까지 영향을 미치게 되어 부작용이 생길 수 있다.

😉 props vs state 구별하기!

  1. 이름 성별 나이 사는곳 취업여부 결혼여부
  • state: 나이 사는곳 취업여부 결혼여부
    props: 이름 성별
  1. toggle switch
  • state : on/off -> true/false
  1. counter
  • state: current value

use props

<Child attribute={value}/>
  1. 하위 컴포넌트에 전달하고자 하는 값과 속성을 정의한다.
  2. props를 이용해 정의된 값과 속성을 전달한다.
  3. 전달받은 props를 렌더링한다.
function Parent() {
  return (
    <div className = "parent">
      <h1>I'm the parent</h1>
      <Child text={"I'm the eldest child"} /> //child text 선언
    </div>
  );
};

function Child(props) { //props로 전달
  return (
    <div className="child">
      <p>{props.text}</p> //dot notation 사용해 jsx에 작성, 렌더링
    </div>
  )
}

props.children

여는 태그와 닫는 태그 사이에 value를 넣어 전달.
props.children으로 접근한다.

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>
  );
}

useState

1. useState import하기

import { useState } from "react";

2. useState 선언하기

const [state 저장 변수, state 갱신 함수] = useState(상태 초기 값);
  • useState를 호출하는 것은 state 변수를 선언하는 것과 같다. state변수는 함수가 끝나도 사라지지 않는다.
  • useState를 호출하면 배열을 반환한다. 배열의 0번째 요소는 현재 state변수, 1번째 요소는 변수를 갱신할 수 있는 함수이다. useState의 인자로 넘겨주는 값은 state의 초기값이다.
function CheckboxExample() {
  const [isChecked, setIsChecked] = useState(false);
}
=== //풀어쓰면
  {
const stateHookArray = useState(false);
const isChecked = stateHookArray[0];
const setIsChecked = stateHookArray[1];
}

3. state변수에 저장된 값 사용하기

jsx 엘리먼트 안에 직접 불러서 사용한다.

<span>{isChecked ? "Checked!!" : "Unchecked"}</span>

4. state 갱신하기

state 변수를 갱신할 수 있는 함수를 호출한다. 여기서는 'setIsChecked'.
input[type=checkbox] 앨리먼트의 값에 따라 isChecked 상태가 변경되어야한다.
체크박스인풋상태가 달라지면 onChange 이벤트가 발생하고 이벤트 핸들러 함수가 작동된다.
onChange 이벤트 발생 -> handleChecked 함수 호출 -> setIsChecked 함수 호출 -> isCheked 변수 갱신 -> 갱신된 isChecked변수 CheckboxExample 컴포넌트에 넘겨줌 -> 렌더링


import React, { useState } from "react";
import "./styles.css";

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>
  );
}

Event

이벤트는 카멜케이스를 사용한다.
jsx를 사용해 이벤트핸들러를 전달한다.

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

onChange

<input><textarea><select> 와 같은 form 앨리먼트의 입력값을 state로 관리한다.
onChange 이벤트 발생 -> input값 확인

function NameForm() {
  const [name, setName] = useState("");
  const handleChange = (e) => {
    setName(e.target.value);
  }

  return (
    <div>
      <input type="text" 
        value={name} 
        onChange={handleChange}></input> 
      //input될때마다 발생하는 e. handleChange함수가 작동함
      //이벤트객체에 담긴 인풋값을 setState를 통해 갱신한다.
      <h1>{name}</h1>
    </div>
  )
};

onClick

함수를 호출하는 것이 아니라 리턴문 안에서 함수를 정의하거나 리턴문 외부에서 함수를 정의 후 이벤트에 함수 자체를 전달해야한다.
arrow function을 사용해서 함수를 정의해야 state에 함수들이 접근할 수 있다.

// 함수 정의하기

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

// 함수 자체를 전달하기

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

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

실습

1

import React, { useState } from "react";
import "./styles.css";

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>
  );
}

export default SelectExample;

2

import React, { useState } from "react";
import "./styles.css";

function App() {
  const [showPopup, setShowPopup] = useState(false);

  const togglePopup = (e) => {
    // Pop up 의 open/close 상태에 따라
    // 현재 state 가 업데이트 되도록 함수를 완성하세요.
    if(showPopup === false){
      setShowPopup(true)
    } else {
      setShowPopup(false)
    }
  };

  return (
    <div className="App">
      <h1>Fix me to open Pop Up</h1>
      {/* 버튼을 클릭했을 때 Pop up 의 open/close 가 작동하도록
          button tag를 완성하세요. */}
      <button onClick={togglePopup} className="open">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>
  );
}

export default App;

controlled component

state를 통제할 수 있는 컴포넌트를 controlled component라고 한다.

import "./styles.css";
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>
      <textarea
        placeholder="여기는 텍스트 영역입니다."
        className="tweetForm__input--message"
        onChange={(e) => setMsg(e.target.value)}
        value={msg}
      ></textarea>
    </div>
  );
}

React 데이터 흐름

상향식으로 앱을 만들기 때문에 테스트가 쉽고 확장성이 좋다.
페이지를 만들기 이전에 컴포넌트를 먼저 만들고 조립한다.
하나의 컴포넌트는 한가지 일만 한다.
컴포넌트는 컴포넌트 바깥에서 props를 이용해 마치 인자나 속성처럼 전달받는다.
데이터를 전달하는 주체는 부모 컴포넌트가 된다.(데이터는 위에서 아래로 흐른다)

상태로 두어야 하는지 여부 판단

  1. 부모로부터 props를 통해 전달되면 state가 아니다.
  2. 시간이 지나도 변하지 않으면 state가 아니다.
  3. 컴포넌트 안의 다른 state나 props를 가지고 계산이 가능하다면 state가 아니다.
  • 하나의 상태가 여러 컴포넌트에 영향을 준다면 공통 소유 컴포넌트가 존재해야한다.
    두개의 자식 컴포넌트가 하나의 상태에 접근려면 두 자식의 공통 부모 컴포넌트에 상태를 위치시킨다.
profile
주니어 플러터 개발자의 고군분투기

0개의 댓글