인프런 커뮤니티 질문&답변

moon님의 프로필 이미지
moon

작성한 질문수

[2024] 한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지

[input 속성 및 state 관리] 사용자 입력 처리하기

해결된 질문

작성

·

476

·

수정됨

0

안녕하세요.

사용자 입력 처리하기 강의 관련 질문입니다.

 

input 태그를 통해 사용자 입력을 받고, 상태 관리하면, 상태에 사용자의 입력이 반영되는 게 한 단계씩 늦는 것 같습니다. (그 이유가 useState가 비동기적으로 처리된다고 들은적이 있는 것 같은데, 정확히 이해가 가지 않아서 질문드립니다.)

 

아래 코드의 handleOnChange함수에서,

Q1) e.target.name, e.target.value은 제깍제깍 실시간으로 반영이 되는데, input state는 한 단계 늦게 반영이 됩니다. 이런 현상이 발생하는 이유는 무엇이고, 이건 개발하는데 문제가 되지 않는 이유는 뭔지? 가 궁금합니다!

 

import { useState } from 'react';

const DiaryEditor = () => {
  const [input, setInput] = useState({
    author: '',
    content: '',
    emotion: 1,
  });

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

  const handleSubmit = () => {
    console.log(input);
    alert('오늘의 일기가 저장되었습니다!');
  };

  return (
    <div className='DiaryEditor'>
      <h2>오늘의 일기</h2>
      <div>
        <input name='author' value={input.author} onChange={handleOnChange} />
        <p>{input.author}</p>
      </div>
      <div>
        <textarea
          value={input.content}
          name='content'
          onChange={handleOnChange}
        />
        <p>{input.content}</p>
      </div>
      <div>
        <span>감정 지수 : </span>
        <select
          onChange={handleOnChange}
          name='emotion'
          value={input.emotion} 
        >
          <option value={1}>1</option>
          <option>2</option>
          <option>3</option>
          <option>4</option>
          <option value={5}>5</option>
        </select>
      </div>
      <div>
        <button onClick={handleSubmit}>저장하기</button>
      </div>
    </div>
  );
};

export default DiaryEditor;


Q2) 위처럼 input이란 state는 한단계씩 늦게 반영이 되는데, select태그의 value 속성을 주는 목적은 무엇인가요??
인풋의 value 속성은 실시간으로 인풋의 값과 상태를 동기화해주는 목적으로 사용한다고 생각했는데,

state가 곧바로 변하지 않는거면, 이 인풋의 value 속성은 무용지물인 것 아닌가라는 생각이 들어 질문드립니다.

 

        <select
          onChange={handleOnChange}
          name='emotion'
          value={input.emotion} 
        >


Q3) useState의 초기값은 반드시 빈문자열등으로 인자를 전달하는 게 나은가요? 아무 인자도 전달하지 않으면 어떤 잠재적인 에러 발생 가능성이 있는건가요?

답변 1

0

이정환 Winterlood님의 프로필 이미지
이정환 Winterlood
지식공유자

안녕하세요 이정환입니다.

우선 useState의 setState가 비동기적으로 동작하는 이유는 컴포넌트가 렌더링 하는 UI를 변경을 반영한 상태로 다시 렌더링해야 하기 때문입니다.

더 구체적으로 말씀드리자면 setState가 호출되었을 때 리액트가 내부적으로 컴포넌트를 다시 호출하여 변경된 State 값이 적용된 UI를 렌더링 하도록 해 화면을 업데이트 하기 위함입니다.

따라서 다음과 같은 함수가 호출되면 React는 함수를 끝 마친 이후에 해당 컴포넌트를 다시 호출해 리렌더를 발생 시키기 때문에 console.log(input) 까지는 변경된 State의 값이 즉시 반영되지 않는 것 입니다.

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

중요한 것은 컴포넌트 역할을 하는 함수 자체가 다시 호출되어야 하기 때문에 이렇게 동작한다고 이해하시면 될 것 같습니다!

<select> 태그의 value 속성을 주는 이유는 앞서 말씀 드린 대로 State가 변경되어 컴포넌트 역할을 하는 함수가 다시 호출되었을 때 변경된 State를 반영한 UI를 렌더링 시키기 위함 입니다.

구체적으로 순서를 나열해보자면 이렇습니다.

  1. 초기 상태 렌더링

  2. setState 호출로 인해 상태 업데이트

  3. React가 내부적으로 상태가 변경된 컴포넌트 재 호출

  4. 재 호출된 컴포넌트는 변경된 State를 반영한 UI를 다시 리턴

 추가로 useState의 초기값으로 ""을 넣어주는 이유는 다음과 같은 경우 오류가 발생할 수 있기 때문에 그렇습니다.

const App() => {
    const [text, setText] = useState(); // text 초기값은 undefined
    return (
        <div>
            {text.toUpperCase()}
            // undefined is not object 에러 발생
        </div>
    );
}

자바스크립트에서는 undefined 값을 객체로 착각하고 메서드를 호출하려고 하거나 프로퍼티에 접근하려고 하면 런타임 오류를 발생시킵니다. 따라서 문자열로 예상될 State의 값을 초기화 할 때에는 undefined으로 초기화 시키는 것 보다 ""을 통해 빈 문자열로 초기화 시켜두는 것이 훨씬 안전합니다.

moon님의 프로필 이미지
moon

작성한 질문수

질문하기