Forms

Jaeseok Han·2023년 10월 29일
0

React Basic

목록 보기
20/30

Controlled Inputs

사용자에게 input 값을 받아 어떻게 사용하는지에 대해서 알아본다.

form 생성

const ControlledInputs = () => {
  return <form className="form">    
    <h4>controlled inputs</h4>
    <div className="form-row">
      <label htmlFor="name" className="form-label">name</label>
      <input type="text" id="name" className="form-input"/>
    </div>
    <div className="form-row">
      <label htmlFor="email" className="form-label">email</label>
      <input type="text" id="email" className="form-input"/>
    </div>
    <button type="submit" className="btn btn-block">
      submit
    </button>
  </form>
};
export default ControlledInputs;

onChange & value

input의 값을 관리하기 위해서는 value, onChange 속성을 사용해야한다.
value는 input의 값을 onChange는 값이 변경될때 값을 설정할 콜백함수를 넣어준다.

  const [name, setName] = useState("");

  const handleChange = (e) => {
    setName(e.target.name)
  }
  
   return <form className="form">    
    <h4>controlled inputs</h4>
    <div className="form-row">
      <label htmlFor="name" className="form-label">name</label>
      <input type="text" id="name" className="form-input" value={name} onChange={handleChange}/>

또는

<input type="text" id="name" className="form-input" value={name} onChange={(e) => setName(e.target.value)}/>

이렇게 되면 초기값은 "" 인 name 값이 input 값으로 지정이 되고 사용자가 input에 값을 넣게되면 name 값이 설정이 되고 input에도 value에 name 값이 들어가게 된다.

onSubmit

const ControlledInputs = () => {
  const [name, setName] = useState("");
  const [email, setEmail] = useState("");

  const handleSubmit = (e) => {
    e.preventDefault();
    //폼 데이터 전송
    console.log(name, email)
  }

  return <form className="form" onSubmit={handleSubmit}>    
    <h4>controlled inputs</h4>
    <div className="form-row">
      <label htmlFor="name" className="form-label">name</label>
      <input type="text" id="name" className="form-input" value={name} onChange={(e) => setName(e.target.value)}/>
    </div>
    <div className="form-row">
      <label htmlFor="email" className="form-label">email</label>
      <input type="text" id="email" className="form-input" value={email} onChange={(e) => setEmail(e.target.value)}/>
    </div>
    <button type="submit" className="btn btn-block">
      submit
    </button>
  </form>
};

onSubmit은 form 내부의 type이 submit인 버튼을 클릭하게 되면 form 데이터를 넘기는 역할을 한다.

💡 e.preventDefault()
일반적으로 이 메서드는 핸들러 내에서 호출되어 기본 동작을 중지시킨다.
예를 들면 폼 제출 버튼을 누르면 페이지가 다시 로드되거나 새로고침되지만 이 메서드를 사용하면 기본 동작을 중지시켜 새로고침이 되지 않는다.

User Challenge

Setup

  • 제어되는 Input(name)을 설정
  • onSubmit 설정 (일단 placeholder 만)
  • 데이터 배열 가져오기 (data 첫번째 배열)
  • 다른 상태 값도 만듦(기본 값은 data)
  • 폼 안에 순환하여 표출(h4)
  • 사용자가 양식을 제출하면 새로운 사람의 목록을 추가
  • 추가 도전 과제
    • 버튼을 추가하고 사용자를 제거하는 기능

data.js

export const data = [
  { id: 1, name: 'john' },
  { id: 2, name: 'peter' },
  { id: 3, name: 'susan' },
  { id: 4, name: 'anna' },
];
const UserChallenge = () => {
  return (
    <div>
      <form className='form'>
        <h4>Add User</h4>
        <div className='form-row'>
          <label htmlFor='name' className='form-label'>
            name
          </label>
          <input type='text' className='form-input' id='name'/>
        </div>

        <button type='submit' className='btn btn-block'>
          submit
        </button>
      </form>
      {/* render users below */}
    </div>
  );
};
export default UserChallenge;

풀이

import { useState } from "react";
import { data } from '../../../data';

const UserChallenge = () => {
  const [name, setName] = useState('');
  const [users, setUsers] = useState(data);

  const handleSubmit = (e) => {
    e.preventDefault();
    if(!name) return;

    const fakeId = Date.now();

    const newUser = {id : fakeId, name}
    const updatedUsers = [...users, newUser];
    setUsers(updatedUsers);
    setName('');
  }

  const handleRemove = (id) => {
    const newUsers = users.filter((value) => id !== value.id);
    setUsers(newUsers)
  }

  const removeUser = (id) => {
    const updatedUsers = users.filter((person) => person.id !== id);
    setUsers(updatedUsers);
  }

  return (
    <div>
      <form className='form' onSubmit={handleSubmit}>
        <h4>Add User</h4>
        <div className='form-row'>
          <label htmlFor='name' className='form-label'>
            name
          </label>
          <input type='text' className='form-input' id='name' value={name} onChange={(e) => setName(e.target.value)}/>
        </div>
        <button type='submit' className='btn btn-block'>
          submit
        </button>
      </form>
      {/* render users below */}
      <h2>users</h2>
      {users.map((user) => {
        return (
          <div key={user.id}>
            <h4>{user.name}</h4>
            <button className="btn" onClick={() => handleRemove(user.id)}>remove</button>
          </div>
        )
      })

      }
    </div>
  );
};
export default UserChallenge;

handleSubmit user정보 추가 이벤트
handleRemove user정보 삭제 이벤트

Multiple Inputs

여러 인풋의 상태값을 다루기 위해서는 name 속성이 필수이다.

name, email, password 값을 하나의 이벤트로 관리하는 법을 알아보자

const MultipleInputs = () => {
  return (
    <div>
      <form className='form'>
        <h4>Multiple Inputs</h4>
        {/* name */}
        <div className='form-row'>
          <label htmlFor='name' className='form-label'>
            name
          </label>
          <input type='text' className='form-input' id='name' />
        </div>
        {/* email */}
        <div className='form-row'>
          <label htmlFor='email' className='form-label'>
            Email
          </label>
          <input type='email' className='form-input' id='email' />
        </div>
        {/* password */}
        <div className='form-row'>
          <label htmlFor='password' className='form-label'>
            Password
          </label>
          <input type='password' className='form-input' id='password' />
        </div>

        <button type='submit' className='btn btn-block'>
          submit
        </button>
      </form>
    </div>
  );
};
export default MultipleInputs;

예시

import { useState } from "react";

const MultipleInputs = () => {
  const [user, setUser] = useState({
    name : '',
    email : '',
    password : ''
  });
  
  const handleChange = (e) => {
    setUser({...user, [e.target.name] : e.target.value})
    console.log(user)
  } 

  return (
    <div>
      <form className='form'>
        <h4>Multiple Inputs</h4>
        {/* name */}
        <div className='form-row'>
          <label htmlFor='name' className='form-label'>
            name
          </label>
          <input type='text' className='form-input' id='name' value={user.name} onChange={handleChange} name="name"/>
        </div>
        {/* email */}
        <div className='form-row'>
          <label htmlFor='email' className='form-label'>
            Email
          </label>
          <input type='email' className='form-input' id='email' value={user.email} onChange={handleChange} name="email"/>
        </div>
        {/* password */}
        <div className='form-row'>
          <label htmlFor='password' className='form-label'>
            Password
          </label>
          <input type='password' className='form-input' id='password' value={user.password} onChange={handleChange} name="password"/>
        </div>

        <button type='submit' className='btn btn-block'>
          submit
        </button>
      </form>
    </div>
  );
};
export default MultipleInputs;

하나의 이벤트(handleChange)로 세가지(name, email, password)의 값을 변경해주고 있다.
setUser() 함수를 통해서 동적 상태 값을 변경해 주고있다.
user 값을 복사하고 동적으로 객체 변수와 input 속성의 name 값이 일치하는 값만 변경하여 상태를 관리하게 된다.

💡 참고사항

  • {x, y}
    이런식으로 객체를 설정해주면 x와 y가 합쳐진 객체를 반환한다.
  • ...user
    객체를 얕은 복사하여 기존값을 변경하지 않고 복사하게 된다.
    만약 user 를 복제하지 않고 직접 수행할 경우 React가 상태 변경을 감지하지 못하고, 상태 변경이 불투명하게 이우러진다.
    React는 불병선을 유지하고 상태가 변경될 때 새로운 상태를 생성하여 상태 변경을 감지하고 관리한다.
  • [e.target.name]
    Computed Property Names으로 JavaScript 문법으로 객체 속성의 이름을 동적으로 생성할 때 유용하며, 객체 속성 이름을 변수나 표현식에서 가져올 때 사용한다.

Other Inputs

checkbox & select

import { useState } from 'react';
const frameworks = ['react', 'angular', 'vue', 'svelte'];
const OtherInputs = () => {
  const [shipping, setShipping] = useState(false);
  const [framework, setFramework] = useState('react');

  const handleShipping = (e) => {
    console.log(e.target.checked);
    setShipping(e.target.checked)
  }

  const handleFramework = (e) => {
    setFramework(e.target.value)
    console.log(framework)
  }

  return (
    <div>
      <form className='form'>
        <h4>Other Inputs</h4>
        {/* name */}
        <div className='form-row' style={{ textAlign: 'left' }}>
          <label htmlFor='shipping'> Free Shipping </label>
          <input 
            type="checkbox" 
            name="shipping" 
            id="shipping"
            checked={shipping} 
            onChange={handleShipping}
          ></input>
        </div>
        <div className='form-row' style={{ textAlign: 'left' }}>
          <label htmlFor='framework' className='form-label'>
            Framework
          </label>
          <select name="framework" id="framework" value={framework} onChange={handleFramework}>
            {frameworks.map((framework) => {
              return(
                <option key={framework}>{framework}</option>
              )
            })}
          </select>
        </div>
        <button type='submit' className='btn btn-block'>
          submit
        </button>
      </form>
    </div>
  );
};
export default OtherInputs;

다른 타입의 input 값도 상태 관리할 수 있다.

0개의 댓글