본문 바로가기
프로그래밍/react

1-7) [리액트 기초] 여러 개의 입력 상태 관리하기

by 플로어코딩 2024. 1. 29.

 

여러 개의 입력 상태 관리

 

많은 홈페이지를 보면 입력창이  간단한  폼 형식으로  되어있지 않고, 다양한 입력 컴포넌트들로 구성되어있다.

회원가입 페이지만 보더라도 사용자로부터 10~ 20개의 항목을 입력 받는다.

 

// src/App.js

import './App.css';
import Header from './components/Header';
import Body from './components/Body';
import Content1 from './components/contents/Content1'
import Footer from './components/Footer';

function App() {
  return (
    <div className="App">
      <Header />		
      <Body>
          <Content1 />   //추가하자
      </Body>
      <Footer />
    </div>
  );
}

export default App;

 

 

src 디렉토리 밑에 contents 디렉토리를 생성하고 Content1.js를 만들자

 

 

<div> 안에 이름, 성별, 나이, 자기소개 칸을 생성하여 관리해보자

 

// src/components/contents/Content1.js

import { useState } from 'react';

const Content1 = () => {
  const [name1, setName1] = useState('');
  const [gender1, setGenger1] = useState('');
  const [age1, setAge1] = useState('');
  const [bio1, setBio1] = useState('');

  const onChangeName1 = (e) => {
    setName1(e.target.value);
  }

  const onChangeGender1 = (e) => {
    setGenger1(e.target.value);
  }

  const onChangeAge1 = (e) => {
    setAge1(e.target.value);
  }

  const onChangeBio1 = (e) => {
    setBio1(e.target.value);
  }
  
  return (
      <div>
          <h3>Content1 추가영역</h3>
          <div>
            <input value={name1} onChange={onChangeName1} placeholder="이름" />
            <select value={gender1} onChange={onChangeGender1}>
              <option value="">선택</option>
              <option value="남자">남자</option>
              <option value="여자">여자</option>
            </select>
            <input value={age1} onChange={onChangeAge1} placeholder="나이" />
            <textarea value={bio1} onChange={onChangeBio1} placeholder="자기소개" />

          </div>
      </div>
  )
}

export default Content1

 

 

 

위 처럼 작성하면 모든 컴포넌트의 동작을 입력받고 관리 할 수 있을 것이다.

하지만 관리하는 측면에서는 코드길이가 많아지기 때문에 관리하는 측면에서는 불편하다.

 

 

객체 자료형을 이용하면 입력 내용이 여러 가지라도 하나의 State에서 관리할 수 있다.

 

위 예제를 아래의 예제와 같이 변경할 수 있다.

좀 더 코드가 간결해지고 관리하기 쉬워졌다는게 느껴질 것이다.

 

// src/components/contents/Content1.js

import { useState } from 'react';

  const Content1 = () => {
	const [state, setState] = useState({
    name1: '',
    gender1: '',
    age1: '',
    bio1: '',
  });

  const handleOnChange = (e) => {
    console.log('현재 수정 대상:', e.target.name);
    console.log('현재 수정 값:', e.target.value);
    setState({
      ...state,
      [e.target.name]: e.target.value,
    });
  }


  
  return (
      <div>
          <h3>Content1 추가영역</h3>
          <div>
            <input name='name1' value={state.name1} onChange={handleOnChange} placeholder="이름" />
            <select name='gender1' value={state.gender1} onChange={handleOnChange}>
              <option value="">선택</option>
              <option value="남자">남자</option>
              <option value="여자">여자</option>
            </select>
            <input name='age1' value={state.age1} onChange={handleOnChange} placeholder="나이" />
            <textarea name='bio1' value={state.bio1} onChange={handleOnChange} placeholder="자기소개" />

          </div>
      </div>
  )
}

export default Content1

 

 

여기서 봐야 할 부분은 handleOnChange 함수에 있는

...state

[e.targe.name] : e.target.value 부분이다.

 

스프레드 연산자를 이용하여 기존 객체의 state 값을 모두 가져오고, 이벥트가 발생한 요소의 name 속성을 가지고 onChange 함수를 발생시켜주는 것이다.

 

 

 

State를 Props로 전달

동적으로 변하는 값은 리액트의 State 역시 일종의 값 이므로 Props로 전달 할 수 있는데...

이번에는 Body에 자식 컴포넌트를 만든 후, Body의 State를 Props로 전달해보는 예제를 다뤄보자

 

 

 

// src/App.js

import './App.css';
import Header from './components/Header';
import Body from './components/Body';
import Content2 from './components/contents/Content2';
import Footer from './components/Footer';

function App() {
  return (
    <div className="App">
      <Header />		
      <Body>
          <Content2 />   //추가하자
      </Body>
      <Footer />
    </div>
  );
}

export default App;

 

 

 

 

// src/components/contents/Content2.js

import '../Body.css';
import { useState } from 'react';

function Viewer({ number }) {
	console.log('Viewer update!! ', number);
	return <div>{number % 2 === 0 ? <h3>짝수</h3> : <h3>홀수</h3>}</div>
}

const Content2 = () => {
  const [number, setNumber] = useState(0);
  const onIncreate = () => {
    setNumber(number + 1);
  }

  const onDecreate = () => {
    setNumber(number - 1);
  }

  return (
      <div>
          <h3>Content2 추가영역 {number} </h3>
          <Viewer number={number} />

          <div>
            <button onClick={onIncreate}>증가</button>
            <button onClick={onDecreate}>감소</button>
          </div>
        </div>
  )
}

export default Content2

 

 

 

 

첫 번째 뜬 Viewer update!!  console은 페이지가 처음 렌더링 할 때 출력된 부분이고

나머지 부분은 부모인 Body 컴포넌트의 State가 변할 때 마다 출력되었습니다.

 

리액트에서는 부모 컴포넌트가 리렌더 되면 자식도 함께 리렌더됩니다.

 

현재 상황은 Body 컴포넌트가 변한다고해서 리렌더 될 이유가 없습니다.

View 컴포넌트의 내용에는 변한게 없기 때문입니다.

 

의미없는 리렌더가 자주 발생하면 웹 브라우저의 성능은 떨어집니다.

따라서 컴포넌트의 부모-자식 관계에서 State를 사용할 때는 늘 주의가 필요합니다.

 

이러한 성능 ㄴ아비를 막는 최적의 기법이 존재합니다.

 

댓글