React 입력 폼 다루기

한상욱·2022년 3월 16일
0
post-thumbnail

📌onChange

리액트에선 순수 HTML과 다르게onChange Prop을 사용하면 입력 값이 바뀔 때마다 핸들러 함수를 실행합니다.oninput 이벤트와 같다고 생각하시면 되는데요.리액트 개발자들은 주로 onChange 라는 Prop을 사용하니까, 이 내용은 꼭 기억해주세요.

📌폼 value를 하나의 객체로 다루기

function TripSearchForm() {
  const [values, setValues] = useState({
    location: 'Seoul',
    checkIn: '2022-01-01',
    checkOut: '2022-01-02',
  })

  const handleChange = (e) => {
    const { name, value } = e.target;
    setValues((prevValues) => ({
      ...prevValues,
      [name]: value,
    }));
  }

  return (
    <form>
      <h1>검색 시작하기</h1>
      <label htmlFor="location">위치</label>
      <input id="location" name="location" value={values.location} placeholder="어디로 여행가세요?" onChange={handleChange} />
      <label htmlFor="checkIn">체크인</label>
      <input id="checkIn" type="date" name="checkIn" value={values.checkIn} onChange={handleChange} />
      <label htmlFor="checkOut">체크아웃</label>
      <input id="checkOut" type="date" name="checkOut" value={values.checkOut} onChange={handleChange} />
      <button type="submit">검색</button>
    </form>
  )
}

state를 하나의 객체로 선언하면 많은 정보를 한 state에 담을 수 있다.
그리고 handleChange를 통해 각 input의 name에 따라 input의 value를 따로 저장할 수 있다. setValues에서 spread문법으로 객체를 저장한다. 그리고 [name]:value를 하면 기존 ...prevValues에 있던 [name] prop의 값만 바뀐다.

📌button의 속성 submit


button에는 type이라는 property가 있는데, 이것이 button을 감싸는 form 태그의 onSubmit과 연결된다. 그래서 버튼을 클릭하면 onSubmit의 메소드가 발동된다.
여기서 주의!!

HTML 폼의 기본 동작은 submit 타입의 버튼을 눌렀을 때 페이지를 이동하는 건데요.

그래서 버튼을 누를 때마다 페이지 이동을 막으려면, 함수에 e.preventDefault()를 실행시켜줘야 한다.

📌제어 컴포넌트

  • 인풋의 value를 react에서 관리한다.
  • react에서 value와 실제 인풋의 value가 항상 같다.
  • 주로 권장되는 방법.

📌비제어 컴포넌트

  • 제어와 반대로 인풋의 value를 react에서 관리하지 않는다.

📌파일 인풋


react에서는 파일을 넣을 때, 비제어 컴포넌트로 만들어줘야 한다.
인풋 태그 안에 value가 없는 것이 그 이유다.

📌useRef

import { useRef } from 'react';
const ref = useRef();
<div ref={ref}> ... </div>

const handleClearClick = () => {
	const refNode = ref.current;
    if (!refNode) return;
	refNode.value =''
  	onChange(name,null)
}

ref객체는 DOM노드를 참조하는 객체이다. 참조하길 원하는 노드 prop으로 써주자.
ref 객체의 current라는 속성으로 참조하길 원하는 DOM 노드 지정 가능.
그리고 참조할 객체가 없을 수도 있으니 없으면 바로 함수를 끝내는 구문도 필요함.
값을 초기화하려면 참조한 노드의 value를 ''처리하면 됨.
물론 부모 컴포넌트의 state에 저장된 value도 null로 바꿔줘야 함.

📌URL 객체

useEffect(()=>{
  if (!value) return;
  
  const nextPreview = URL.creatObjectURL(value);
  setPreview(nextPreview)
  
  return () =>{
    setPreview();
    URL.revokeObjectURL(nextPreview)
  }
},[value])

먼저 value에 아무 값도 안 담기면 실행하지 않기 위해 if (!value) return을 넣어준다.
그리고 value에는 img.file값이 담겨 있는데, createObjectURL을 통해 URL 객체를 생성한다.
이 때 이 객체가 사이드 이펙트. 즉 메모리를 차지하는 놈이다. 그래서 안 쓰는 URL 객체는 없애줘야 한다.
revokeObjectURL이 이 URL 객체를 없애주는 놈이다.

📌사이드 이펙트

useEffect는 리액트 컴포넌트 함수 속에서 사이드 이펙트를 발동하고 싶을 때 쓰는 코드이다.
직접 DOM 노드를 변경하거나, 브라우저에 데이터 저장, 네트워크에 리퀘스트를 보낼 때 말이다.
주로 리액트 외부에 있는 데이터나 상태를 이용할 때 사용한다.

useEffect(() => {
  document.title = title;// 페이지 데이터를 변경
}, [title]);

useEffect(() => {
  localStorage.setItem('theme', theme);// 로컬 스토리지에 테마 정보를 저장
}, [theme]);// 참고: localStorage 는 웹 브라우저에서 데이터를 저장할 수 있는 기능입니다.

useEffect는 동기화에 유용한 코드이다.
여기서 동기화는 컴포넌트 안에 데이터와 리액트 밖의 데이터를 일치시키는 것이다.

📍정리 함수

useEffect(() => {
// 사이드 이펙트
//  return () => {
// 사이드 이펙트에 대한 정리
//  }
}, [dep1, dep2, dep3, ...]);


// ex)
useEffect(() => {
    const timerId = setInterval(() => {
      console.log('타이머 실행중 ... ');
      setSecond((prevSecond) => prevSecond + 1);
    }, 1000);
    console.log('타이머 시작 🏁');

    return () => {
      clearInterval(timerId);
      console.log('타이머 멈춤 ✋');
    };
  }, []);

useEffect에서 사이드 이펙트를 만들면 메모리를 잡아먹기 때문에 정리할 필요가 있다.
이때 콜백함수의 리턴 함수로 정리 함수를 선언할 수 있다.

📎정리 함수가 실행되는 시점

쉽게 말해서 콜백을 한 번 실행했으면, 정리 함수도 반드시 한 번 실행된다고 생각하면 됩니다.정확히는 새로운 콜백 함수가 호출되기 전에 실행되거나 (앞에서 실행한 콜백의 사이드 이펙트를 정리), 컴포넌트가 화면에서 사라지기 전에 실행됩니다 (맨 마지막으로 실행한 콜백의 사이드 이펙트를 정리).

아무튼 사이드 이펙트 안 쓰는데 냅두면 메모리 아까우니 꺼줘야 좋음.

profile
하고 싶은 게 많은 사람

0개의 댓글