[React] ref 대신 state 사용하기

suno·2022년 12월 7일
0
post-custom-banner

input에 todo를 입력하고 Submit하면, 아래 리스트에 todo가 추가되는 간단한 리액트 앱을 만들고 있는데,
DOM 요소에서 값을 가져오는 과정에 의문이 생겼다.

DOM API 사용을 고민하다가 useRef를 사용하고, 최종적으로 state로 변경했다.




1) useRef 사용

import React, { useRef } from 'react';
import { v4 as uuid } from 'uuid';

export default function AddForm({ todos, setTodos }) {
  const todoRef = useRef(null); // input DOM을 참조할 ref 생성

  const addTodo = (event) => {
    event.preventDefault();
    const todo = todoRef.current.value;
    setTodos((prev) => [...prev, { todo, isDone: false, id: uuid() }]);
    todoRef.current.value = '';
    todoRef.current.focus();
  };
  
  return (
    <div className='addform__container'>
      <form className='addform' onSubmit={addTodo}>
        <label className='addform__label' htmlFor='new-todo'>
          To Do{' '}
        </label>
        <input
          className='addform__input'
          type='text'
          id='new-todo'
          name='new-todo'
          ref={todoRef} // todoRef가 input DOM을 참조함
          autoFocus={true}
        />
        <input className='btn addform__submit' type='submit' value='추가' />
      </form>
    </div>
  );
}

의식의 흐름 🤔

  1. submit은 form 태그에서 일어나는 이벤트니까, addTodo 함수의 event.target은 form이 된다.
  2. addTodo 함수에서는 input의 value를 받아와서 todo 객체를 만들고, todos 배열에 추가해야 한다.
  3. 그렇다면 DOM API querySelector로 input DOM을 선택하고, value 값을 가져오면 되지 않을까?
  4. React에서는 DOM API 사용을 지양해야 한다고...?
  5. useRef라는 메소드가 있네! 이걸 사용하면 되겠다!
  6. 매니저님 피드백 & 폭풍 검색 → React는 state가 우선이다. ref를 사용하지 않는 방법이 있을까?
  7. input의 value를 관리하는 state를 만들어서, input이 변경될 때 state를 업데이트 해주자!



2) state 사용

import React, { useState } from 'react';
import { v4 as uuid } from 'uuid';

export default function AddForm({ setTodos }) {
  const [todoValue, setTodoValue] = useState(''); // input value를 state로 관리, 초기값은 빈 문자열

  const handleChange = (e) => {
    setTodoValue(e.target.value); // input 값이 변경되면 todoValue 업데이트
  };

  const addTodo = (event) => {
    event.preventDefault();
    const todo = todoValue; // todo 추가할 때 todoValue를 바로 사용
    setTodos((prev) => [...prev, { todo, isDone: false, id: uuid() }]);
    setTodoValue(''); // todo 추가 완료되면 todoValue를 다시 빈 문자열로 변경
  };
  
  return (
    <div className='addform__container'>
      <form className='addform' onSubmit={addTodo}>
        <label className='addform__label' htmlFor='new-todo'>
          To Do{' '}
        </label>
        <input
          className='addform__input'
          type='text'
          id='new-todo'
          name='new-todo'
          onChange={handleChange} // value 값이 변경되면 함수 호출
          autoFocus={true} // autoFocus 속성으로 submit 후 자동 포커스
          value={todoValue} // value를 todoValue로 지정 -> todo 추가 완료 후 빈 문자열로 변경
        />
        <input className='btn addform__submit' type='submit' value='추가' />
      </form>
    </div>
  );
}

ref를 사용하는 대신 input의 value를 state로 관리하도록 변경했다.
DOM에 직접 접근하지 않아도 되어 훨씬 간단하고 보기에도 깔끔한 코드가 되었다.




그러나,,, input 이벤트가 발생할 때마다 handleChange 함수를 호출하는 것이 과연 바람직한 로직인지? 의문이 들기는 한다.
이건 튜터님께 물어봐야겠다!

+ 튜터님께 물어본 결과,,, 현업에서도 굉장히 많이 쓰이는 방식이라고 한다.
Ref보다는 확실히 효율적인 방법인거 같으니 걱정말고 사용해야지!

profile
Software Engineer 🍊
post-custom-banner

0개의 댓글