똑같은 삽질은 2번 하지 말자

헷갈리는 Checkbox와 Radio의 컴포넌트 본문

카테고리 없음

헷갈리는 Checkbox와 Radio의 컴포넌트

곽빵 2024. 1. 27. 20:10

개요

React, Vue를 활용해 개발을 하는 중인데 Vue일때는 이런식으로 개발을 하고 React일때는 이런식으로 개발을 하는등등 방식이 다르고 근본적이 처리에 대해 제대로 인식이 안되어 있는 듯해 이 글을 작성하면서 정리하고자 한다.

용도

  • Radio: 일반적으로 사용자가 주어진 옵션 중 하나만 선택할 수 있을 때 사용된다. 같은 이름(name 속성)을 공유하는 라디오 버튼 그룹에서는 오직 하나의 옵션만이 선택될 수 있어야 한다.
  • Checkbox: 사용자가 여러 옵션을 동시에 선택할 수 있게 해준다. 각 체크박스는 독립적으로 동작하며, 여러 옵션을 동시에 선택/선택 해제할 수 있어야 한다.

Vue로 구현하기

Radio

<input type="radio" v-model="picked" value="One">
<input type="radio" v-model="picked" value="Two">

일반적으로 v-model을 사용하여 단일 데이터 속성에 바인딩한다. 라디오 버튼 그룹 내의 모든 버튼이 같은 v-model을 공유하며, 선택된 라디오 버튼의 value가 picked에 할당된다.

 

Checkbox

<input type="checkbox" v-model="checkedNames" value="Jack">
<input type="checkbox" v-model="checkedNames" value="John">

개별 체크박스는 각각의 데이터 속성에 바인딩할 수 있으며, 또한 v-model을 배열에 바인딩하여 여러 체크박스를 그룹화할 수도 있다. 체크박스의 value는 체크되었을 때 v-model에 바인딩된 배열에 추가되고, 체크 해제되면 배열에서 제거된다.

 

Vue의 경우에는 v-model을 활용하면 상당히 심플하게 Radio와 Checkbox를 구현할 수 있다.

React로 구현하기

Radio

function RadioExample() {
  const [selectedOption, setSelectedOption] = useState('option1');

  const handleChange = (event) => {
    setSelectedOption(event.target.value);
  };

  return (
    <div>
      <label>
        <input
          type="radio"
          checked={selectedOption === 'option1'}
          onChange={handleChange}
        />
        Option 1
      </label>
      <label>
        <input
          type="radio"
          checked={selectedOption === 'option2'}
          onChange={handleChange}
        />
        Option 2
      </label>
    </div>
  );
}

 

Checkbox

function CheckboxExample() {
  const [checkedItems, setCheckedItems] = useState(new Map());

  const handleChange = (event) => {
    const item = event.target.name;
    const isChecked = event.target.checked;
    setCheckedItems(prev => new Map(prev).set(item, isChecked));
  };

  return (
    <div>
      <label>
        <input
          type="checkbox"
          checked={checkedItems.get('item1') || false}
          onChange={handleChange}
        />
        Item 1
      </label>
      <label>
        <input
          type="checkbox"
          checked={checkedItems.get('item2') || false}
          onChange={handleChange}
        />
        Item 2
      </label>
    </div>
  );
}

 

리액트의 경우에는 v-model이 단독으로 해주던걸 각각 checked와 onChange로 나누어서 조금 더 구체적으로 처리를 해야 한다. (물론 위와 다른 방식으로도 구현할 수 있다. )

컴포넌트로 구현하기(Vue, React 공통)

개별 컴포넌트로 만들려고 할 때 props를 어떻게 구성하지? 에 대해 항상 고민하는데 이는 요구사항에 따라 달라질 수 있겠지만 라디오나 체크박스 컴포넌틑는 오로지 UI적인 요소만 가지는 Dumb한(멍청한)? 컴포넌트로 만드는게 좋다. 왜냐하면 Dumb Component로 만들어서 UI적인 요소만 잘라내면 거의 모든패턴에 재활용이 가능하기 때문이다.

 

그럼 CheckBox의 Props를 생각해보자

type CheckBoxItemBaseType = {
  text: string;
  checked: boolean;
  disabled?: boolean;
  indeterminate?: boolean;
  change: (checked: booelan) => void;
};
  • text: 체크박스의 라벨
  • checked: 현재 체크가 되어 있는지의 여부
  • diabled: 비활성화 여부
  • indeterminate: 중간체크 여부 (보통 전체체크 체크박스가 별도로 존재하며 그 하위의 체크박스가 일부만 체크되어 있을때 true가 된다.)
  • change: 핸들링 메소드

여기서 value를 props로 받지 않고있는 이유는 보통 value는 부모 컴포넌트에서만 알고 있으면 되고 체크박스 컴포넌트는 checked값만 알고 있으면 문제가 없다.

 

라디오의 경우는 이하의 props를 가지도록 구성한다.

type RadioProps {
  readonly checkedKey: string | number | boolean;
  readonly disabled?: boolean;
  readonly radioItems: {radioKey: string | number | boolean, text: string};
}
  • checkedKey: 현재 체크되어 있는 값, radioItems안에 있는 radioKey값과 비교해서 현재 체크된 라디오를 구별할 수 있다.
  • disabled: 비활성화 여부
  • radioItems: 라디오로 들어갈 친구들의 정보

라디오의 경우에는 절대적으로 복수의 라디오 버튼이어야 UI로써의 기능을 하기 때문에 애초에 radioItems로 복수의 라디오 버튼을 표시하게끔 한다.

Comments