혼자 적어보는 노트

[React] select 사용하여 option구현 (장바구니옵션) 본문

React

[React] select 사용하여 option구현 (장바구니옵션)

jinist 2021. 12. 5. 10:59

 

하고자 하는 기능은

상품 데이터에 옵션이 있고, 옵션선택 시 

옵션이 하단에 표시되고 count까지 할 수 있는 기능을 구현하려 한다.

 

 

const [selectedOption, setSelectedOption] = useState("");

const { id, name, price, image, description, option } = currentProduct;
//currentPropdoct에는 상품의 데이터가 담겨있다.


const haldleOptionSelect = (e) => {
  setSelectedOption(e.target.value);
  console.log(selectedOption); //선택된 옵션을 확인할 수 있다.
};
  
//..생략

<select onChange={haldleOptionSelect}>
  <option value="">옵션을 선택해주세요</option>
  {option.color.map((item, i) => (
    <option value={item} key={i}>
      {item}
    </option>
  ))}
</select>

위와 같이 onChange과 useState를 사용하여 선택된 옵션을 알아낼 수 있다.

 

옵션이 선택되면 하단에 선택된 옵션들을 나열해주는 UI를 만들어야 한다.

 

  const [selectedOption, setSelectedOption] = useState("");
  const [selectedOptions, setSelectedOptions] = useState([]);
  
   const haldleOptionSelect = (e) => {
    setSelectedOption(e.target.value);
    if (!e.target.value) {
      return;  // "옵션을 선택해주세요" 라는 옵션 선택 시 담기지 않게 처리
    }
    const selected = {
      optionName: e.target.value,
      quan: 1, // 수량의 기본값은 일단 1으로 주었다.
    };
    if (
      selectedOptions.some((item) => item.optionName == selected.optionName)
    ) {
      alert("이미 추가된 옵션입니다.");
      // 이미 추가된 옵션을 다시 클릭했을 경우 알림창을 띄운다.
      return;
    }
    setSelectedOptions([...selectedOptions, selected]);
    //  선택된 옵션들을 담아준다.
  };
  
  
  //..생략
  
  <select onChange={haldleOptionSelect}>
    <option value="">옵션을 선택해주세요</option>
    {option?.color.map((item, i) => (
      <option value={item} key={i}>
        {item}
      </option>
    ))}
  </select>
  <ul className="selected-option-list">
    {selectedOptions.length > 0 //selectedOptions에 값이 있을 때 노출하게 설정
      ? selectedOptions.map((item) => (
          <li>
            <span>{item.optionName}</span>
            <span>{item.quan}</span>
          </li>
        ))
      : null}
  </ul>

위와 같이 코드 작성 시 옵션 selected시 옵션 아래에

selectedOptions에 담은 각각의 optionName과 quan이 출력된다.

빈 값, 중복 값이 담기지 않게 처리까지 하였으니

추가된 값에 맞게 input을 만들어보자.

 

 

//..생략

const increase = (index) => {
    const copy = [...selectedOptions];
    copy[index].quan++;
    setSelectedOptions(copy);
  };
  const decrease = (index) => {
    const copy = [...selectedOptions];
    if (copy[index].quan > 1) { //  quan이 1 아래로는 떨어지지 않도록 한다.
      copy[index].quan--;
      setSelectedOptions(copy);
    }
  };


//..생략

<ul className="selected-option-list">
{selectedOptions.length > 0
  ? selectedOptions.map((item, index) => (
      <li>
        <span>{item.optionName}</span>
        <button
          className="plus-btn"
          onClick={() => {
            increase(index); //각각의 index를 전달해준다.
          }}
        >
          +
        </button>
        <input type="tel" value={item.quan} />
        // 해당 item의 quan의 값을 value로 설정
        <button
          className="minus-btn"
          onClick={() => {
            decrease(index);
          }}
        >
          -
        </button>
      </li>
    ))
  : null}
</ul>

해당 데이터의 quan에 맞게 input을 출력하는 것은 간단했지만

작업을 하다보니 메인 페이지에서 장바구니를 즉석에서 담는 기능을 작업할 때

해당 기능을 한번 더 쓸 듯 하여 hooks로 만들어서 관리하기로 했다.

 

//hooks

export const useOption = () => {
  const [selectedOption, setSelectedOption] = useState("");
  const [selectedOptions, setSelectedOptions] = useState([]);
  const copy = [...selectedOptions];
  const optionSelect = (e) => {
    setSelectedOption(e.target.value);
    if (!e.target.value) {
      return;
    }
    const selected = {
      optionName: e.target.value,
      quan: 1,
    };
    if (
      selectedOptions.some((item) => item.optionName == selected.optionName)
    ) {
      alert("이미 추가된 옵션입니다.");
      return;
    }
    setSelectedOptions([...selectedOptions, selected]);
  };
  const increase = (index) => {
    copy[index].quan++;
    setSelectedOptions(copy);
  };
  const decrease = (index) => {
    if (copy[index].quan > 1) {
      copy[index].quan--;
      setSelectedOptions(copy);
    }
  };
  return {
    increase,
    decrease,
    optionSelect,
    selectedOptions,
  };
};

 

 

Comments