Language/React.js

[React] State로 상태 관리하기

JJcoding 2024. 10. 16. 14:56

State란?

  • useState() 함수는 리턴 값으로 두 개를 반환한다.
    첫 번째 요소는 state로 선언된 변수이고, 두 번째 요소는 상태 변환 함수이다.
  • 두 개의 값이 있으므로 처음부터 ‘구조 분해 할당’ 을 활용해 배열로 받는것이 일반적이다.
  • 리렌더링이란?
    • 쉽게 말해 state 값이 변경되면 return을 다시한다. 즉 변경된 state 값으로 화면을 다시 그린다.

App.jsx

import "./App.css";
import { useState } from "react";

function App() {
  const [count, setcount] = useState(0);
  const [light, setLight] = useState("OFF");

  return (
    <>
      <div>
        <h1>{light}</h1>
        <button
          onClick={() => {
            setLight(light === "ON" ? "OFF" : "ON");
          }}
        >
          {light === "ON" ? "끄기" : "켜기"}
        </button>
      </div>
      <div>
        <h1>{count}</h1>
        <button
          onClick={() => {
            setcount(count + 1);
          }}
        >
          +
        </button>
      </div>
    </>
  );
}

export default App;
  • state를 사용하지 않고 일반변수 let light를 만들어서 똑같이 코드를 작성하면 되는 것 아닌가?
    • 일반 변수는 ‘리렌더링’이 하지 않기 때문에 화면이 바뀌지 않는다.
    • 리액트 컴포넌트는 state 값이 변화될 때만 리렌더링을 하기 때문에 state로 처리해야 한다.

State를 Props로 전달하기

  • 리액트에서 리렌더링이 진행되는 경우 세 가지
    1. 자신이 관리하는 state의 값이 변경 되었을 때
    2. 자신이 제공받는 props의 값이 변경 되었을 때
    3. 부모 컴포넌트가 리런데링 되었을 때
  • 서로 다른 기능을 하는 두 개의 state를 같은 컴포넌트 안에 넣을 경우, 부모 컴포넌트의 리렌더링으로 인해 상관없는 다른 state 역시 불필요하게 리렌더링 되어 성능 저하를 일으킨다.
  • 따라서 기능 별로 컴포넌트를 나누어 관리해야 한다.

Bulb.jsx

import { useState } from "react";

const Bulb = () => {
  const [light, setLight] = useState("OFF");

  console.log(light);
  return (
    <div>
      {light === "ON" ? (
        <h1 style={{ backgroundColor: "orange" }}>ON</h1>
      ) : (
        <h1 style={{ backgroundColor: "gray" }}>OFF</h1>
      )}

      <button
        onClick={() => {
          setLight(light === "ON" ? "OFF" : "ON");
        }}
      >
        {light === "ON" ? "끄기" : "켜기"}
      </button>
    </div>
  );
};

export default Bulb;
  • 전구를 켜고 끄는 기능

Counter.jsx

import { useState } from "react";

const Counter = () => {
  const [count, setcount] = useState(0);

  return (
    <div>
      <h1>{count}</h1>
      <button
        onClick={() => {
          setcount(count + 1);
        }}
      >
        +
      </button>
    </div>
  );
};

export default Counter;
  • 버튼을 클릭하면 숫자가 올라가는 기능

App.jsx

import "./App.css";
import Bulb from "./components/Bulb";
import Counter from "./components/Counter";

function App() {
  return (
    <>
      <Bulb />
      <Counter />
    </>
  );
}

export default App;
  • 두 개의 컴포넌트를 자식 컴포넌트로 가지고 있는 부모 컴포넌트
  • Counter 버튼을 클릭해도 Bulb의 영향이 가지 않고, Bulb 버튼을 클릭해도 Counter의 영향이 없다.

State로 사용자 입력 관리하기

  • 간단히 회원가입 폼을 만들기

Register.jsx

import { useState } from "react";

// 간단한 회원가입 폼
// 1. 이름
// 2. 생년월일
// 3. 국적
// 4. 자기소개

const Register = () => {
  const [name, setName] = useState("이름");
  const [birth, setBirth] = useState("");
  const [country, setCountry] = useState("");
  const [bio, setBio] = useState("");

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

  const onChangeBirth = (e) => {
    setBirth(e.target.value);
  };

  const onChangeCountry = (e) => {
    setCountry(e.target.value);
  };

  const onChangeBio = (e) => {
    setBio(e.target.value);
  };

  return (
    <div>
      <div>
        <input value={name} onChange={onChangeName} placeholder={"이름"} />
      </div>
      <div>
        <input value={birth} type="date" onChange={onChangeBirth} />
      </div>
      <div>
        <select value={country} onChange={onChangeCountry}>
          <option></option>
          <option value="kr">한국</option>
          <option value="us">미국</option>
          <option value="cn">중국</option>
        </select>
      </div>
      <div>
        <textarea value={bio} onChange={onChangeBio} />
        {bio}
      </div>
    </div>
  );
};

export default Register;

 

  • 하나의 객체값으로 통합하고 스프레드 연산자를 사용해 중복코드 제거하기
import { useState } from "react";

const Register = () => {
  const [input, setInput] = useState({
    name: "",
    birth: "",
    country: "",
    bio: "",
  });

  console.log(input);

  const onChangeName = (e) => {
    setInput({
      ...input,
      name: e.target.value,
    });
  };

  const onChangeBirth = (e) => {
    setInput({
      ...input,
      birth: e.target.value,
    });
  };

  const onChangeCountry = (e) => {
    setInput({
      ...input,
      country: e.target.value,
    });
  };

  const onChangeBio = (e) => {
    setInput({
      ...input,
      bio: e.target.value,
    });
  };

  return (
    <div>
      <div>
        <input
          value={input.name}
          onChange={onChangeName}
          placeholder={"이름"}
        />
      </div>
      <div>
        <input value={input.birth} type="date" onChange={onChangeBirth} />
      </div>
      <div>
        <select value={input.country} onChange={onChangeCountry}>
          <option></option>
          <option value="kr">한국</option>
          <option value="us">미국</option>
          <option value="cn">중국</option>
        </select>
      </div>
      <div>
        <textarea value={input.bio} onChange={onChangeBio} />
      </div>
    </div>
  );
};

export default Register;

 

  • 중복되는 이벤트 핸들러도 통합 이벤트 핸들러로 만들기
import { useState } from "react";

const Register = () => {
  const [input, setInput] = useState({
    name: "",
    birth: "",
    country: "",
    bio: "",
  });

  const onChange = (e) => {
    setInput({
      ...input,
      [e.target.name]: e.target.value,
    });
  };

  return (
    <div>
      <div>
        <input
          name="name"
          value={input.name}
          onChange={onChange}
          placeholder={"이름"}
        />
      </div>
      <div>
        <input
          name="birth"
          value={input.birth}
          type="date"
          onChange={onChange}
        />
      </div>
      <div>
        <select name="country" value={input.country} onChange={onChange}>
          <option></option>
          <option value="kr">한국</option>
          <option value="us">미국</option>
          <option value="cn">중국</option>
        </select>
      </div>
      <div>
        <textarea name="bio" value={input.bio} onChange={onChange} />
      </div>
    </div>
  );
};

export default Register;

  • [e.target.name]: e.target.value 이 부분이 중요한데, key : value로 작동한다.
  • 자바 스크립트의 객체 프로퍼티(객체 속성) 문법을 이용한 것으로, 대괄호 안에 어떤 변수명을 넣으면 프로퍼티의 key로써 설정이 된다는 점!

 

출처 : 한입 크기로 잘라먹는 리액트