리액트에서 폼 요소의 기본값 설정하기 - value와 defaultValue

짱유경·2021년 4월 16일
1

React

목록 보기
2/3
post-thumbnail

📌 TL;DR

  1. 값이 변경되지 않는, 읽기전용인 값은 value로 정의하기
  2. 값이 변경되고, 기본값이 있는 요소는 defaultValue로 정의하기
  3. defaultValue로 설정시 selected가 안될때, key속성과 같이 사용하기 (예: key={value} defaultValue={value})
  4. 외부 API로 받아오는 것과 같이 불규칙한 값에 selected가 안될때 key값을 value로 지정하지 말고 uuid와 같은 유니크한 값을 적용해주자!

🤔 폼 요소의 기본값, 어떻게 설정하지?

셀렉트 박스를 기준으로. 일반적인 javascript와 html에서는 selected 속성을 사용해 선택된 기본값을 설정한다. 하지만 리액트에선 selected 속성 대신 value를 사용해 기본값을 정의한다.

<select value="2">
  <otpion value="1">1</option>
  <otpion value="2">2</option>
</select>

일반적으로 value로 기본값을 사용하면 값이 읽기전용으로 취급되어 값이 변경되지 않는다. (사진상 첫번째 컴포넌트) 이때 defaultValue 속성을 사용하면, 비제어 컴포넌트로 활용하면서 변경되는 값으로 사용할 수 있다.

React 렌더링 생명주기에서 폼 엘리먼트의 value 어트리뷰트는 DOM의 value를 대체합니다. 비제어 컴포넌트를 사용하면 React 초깃값을 지정하지만, 그 이후의 업데이트는 제어하지 않는 것이 좋습니다. 이러한 경우에 value 어트리뷰트 대신 defaultValue를 지정할 수 있습니다.

하지만 defaultValue에 사용될 value값을 부모 컴포넌트에서 내려줄 때, 외부에서 받아온 데이터 값 (api 요청으로 받아온 값)으로 내려주면 값이 선택되지 않는 문제가 있었다. (사진상 두번째 컴포넌트)

When the source prop changes, the loading state should always be overridden. Conversely, the state is overridden only when the prop changes and is otherwise managed by the component.

✨ key 속성 추가하기

처음에는 컴포넌트의 마운트/언마운트와 관련된 줄 알고 useEffect()setState()에서 내려받은 값을 다시 관리했었는데, 이는 안티패턴 이었다. props로 전달받은 값을 state에 복사하면, 이후의 모든 업데이트 값이 무시된다. 관련된 설명은 Dan Abramov의 블로그에 잘 설명되어 있다.

react의 공식문서에도 나와있듯이 이런 상황에서 권장되는 방법은 제어 컴포넌트 방식인 value를 사용하는 것과 완전한 비제어 컴포넌트 방식을 사용하는 것인데, 제어 컴포넌트를 사용하면 위와 같이 값을 변경할 수 없게 되므로 나는 후자의 방식을 선택했다.

<select key={value} defaultValue={value}>
  <option value="1">1</option>
  <option value="2">2</option>
  <option value="3">3</option>
  <option value="4">4</option>
</select>

기본값도 제대로 잘 적용되고, 값도 잘 변경되는 모습..!

이 방식은 키가 변경될 때 마다 모든 요소들이 갱신되고 재생성된다. key방식에 대한 자세한 설명은 여기에 잘 나와있다.

DOM 노드의 자식들을 재귀적으로 처리할 때, React는 기본적으로 동시에 두 리스트를 순회하고 차이점이 있으면 변경을 생성합니다.
예를 들어, 자식의 끝에 엘리먼트를 추가하면, 두 트리 사이의 변경은 잘 작동할 것입니다.
자식들이 key를 가지고 있다면, React는 key를 통해 기존 트리와 이후 트리의 자식들이 일치하는지 확인합니다. 인덱스를 key로 사용 중 배열이 재배열되면 컴포넌트의 state와 관련된 문제가 발생할 수 있습니다. 컴포넌트 인스턴스는 key를 기반으로 갱신되고 재사용됩니다. 인덱스를 key로 사용하면, 항목의 순서가 바뀌었을 때 key 또한 바뀔 것입니다.

유니크한 키값

21.07.29 추가

외부 API를 통해 받아오는 값의 경우 key를 value와 같은 값으로 설정해두면 값이 제대로 선택되지 않는 오류가 있다. 이 경우에는 key가 유니크한 값이 아니어서 이러한 오류가 생길 수 있다.

Math.random()과 같은 값으로 key를 랜덤하게 지정해줄 수 있지만, 공식문서에 의하면 다음과 같은 이유로 비추천한다.

key는 반드시 변하지 않고, 예상 가능하며, 유일해야 합니다. 변하는 key(Math.random()으로 생성된 값 등)를 사용하면 많은 컴포넌트 인스턴스와 DOM 노드를 불필요하게 재생성하여 성능이 나빠지거나 자식 컴포넌트의 state가 유실될 수 있습니다.

한마디로 변하는 값으로 key를 지정하면 성능 부분에서 문제가 생길 수 있음을 얘기한다. 그래서 찾은 해결책이 uuid를 사용하는 방법인데, key를 uuid의 고유한 값으로 설정해두면 외부에서 받아온 값으로 selected를 지정해도 확실히 잘 선택된다.

npm i react-uuid
import uuid from "react-uuid"

// ...

return (
  <select key={uuid()} value={value}>
  </select>
)

👏 마치며

이 문제로 며칠간 많이 고민했는데, 생각외로 간단한 문제였다. 오늘도 역시 공식문서는 위대하다는 깨달음을 얻게 되었다... 또, 그냥 쓰라고 해서 썼던 key요소의 중요성을 다시한번 깨닫게 되는 순간이었다.

의역과 축약이 많이 들어가 있는데, 자세한 원문 내용은 여기에서 확인하는 걸 권장한다.


틀린 내용이 있다면 댓글 남겨주세요 ! 🙇‍♀️ 감사합니다

0개의 댓글