본문 바로가기
Web Development/React

[ React ] React Select library를 사용해 태그 생성 및 태그 추가 기능 구현

by Krystal K 2023. 7. 31.

 React Select library를 사용해 태그 생성 및 태그 추가 기능 구현

 

해당 기능을 개발하게 된 배경

인플루언서와 클라이언트를 매칭하는 광고 플랫폼 회사에서 인턴으로 근무할 당시

사내의 TF팀에서 진행하는 admin system 개발 프로젝트에 참여하게 되었습니다.

해당  프로젝트는 인플루언서 데이터를 효율적으로 관리하기 위한 내부용 admin page 개발이 목표였습니다.

 

기능을 개발하는 중간에 기획이 변경되어 동료가 맡았던 인플루언서 태그 기능의 볼륨이 초반 계획보다 커지게 되었습니다.

그러한 이유로 태그 생성하는 select box와 관련된 기능들을 구현해서 동료에게 전달하는 방식으로 업무가 수정되었습니다.

따라서 태그 생성과 관련된 코드들이 기존에 동료가 작성했던 코드를 수정하거나,

추가적으로 동료가 다시 이어서 개발을 진행해야 하는 상황이라 미완성의 상태로 남겨둔 부분들 또한 있습니다.  

이러한 상황을 고려하여 읽어주시기 바랍니다.

 

기존의 방식

기존에 동료가 기획한 방식은 태그 목록을 불러와서 검색하고 태그를 해당 인플루언서에게 추가하는 select box 와

새로운 태그를 생성하는 input창을 분리해서 진행하는 방식

 

새로운 방식

React Select 라이브러리를 사용

그러나 react select에서 제공하는 기능 중 creatable 기능 사용

 목록에 없는 태그를 사용자가 검색할 경우 태그 생성하기 버튼이 select box 하단에 나타나도록 구현

 

그렇게 한 이유

이렇게 함으로서 불필요한 input 창을 없애 간결한 UI 구성이 가능하다.

사용자가 태그를 검색하기 위해 한번, 새로 생성하기 위해 또 한번 텍스트를 입력해야하는 번거로움을 없앴다.

 


react Select 를 선택한 이유

 

 https://react-select.com/home

 

React-Select

A flexible and beautiful Select Input control for ReactJS with multiselect, autocomplete and ajax support.

jedwatson.github.io

https://www.npmjs.com/package/react-select

 

react-select

A Select control built with and for ReactJS. Latest version: 5.7.4, last published: 18 days ago. Start using react-select in your project by running `npm i react-select`. There are 6164 other projects in the npm registry using react-select.

www.npmjs.com

 

1. 이미 프로젝트 내에서 사용중이다.

새로운 라이브러리를 사용할 때 고려해야 할 사항 중 하나가 버전 충돌인데 그런 문제로부터 자유로웠습니다.

또한 이미 사용중이기 때문에 이 기능을 재사용 가능한 컴포넌트로 만들면 좋을 것 같았습니다.

 

2. 커스터마이징이 쉽고 기본 제공되는 소스들을 이용해 프로젝트에 바로 적용할 수 있다.

단기간에 결과물을 만들어야하는 tf팀으로 디자이너가 없이 프로젝트를 진행

UI  통일성을 위해 tailwind css를 사용하고, tailwind에서 제공되는 style component를 적용하여 프로젝트를 진행중이었습니다.

단기간에 결과물을 내야하는 상황에서 UI 구현을 가장 빠르게 할 수 있는 라이브러리였습니다.

기본적으로 제공되는 컴포넌트의 형태가 프로젝트에서 추구하는 UI 디자인과 유사하여 빠르게 결과물을 볼 수 있었습니다.

 

3. 태그 검색, 추가 및 생성을 한번에 할 수 있다.

태그 검색 및 추가, 신규 태그 생성이 한번에 가능하다는 것은 두가지 측면에서 긍정적인 결과를 가져옵니다.

첫번째, 작성해야하는 코드의 양이 줄어들어 가독성이 증가하고 코드가 간결해져 유지보수가 용이해집니다.

두번째, 하나의 select box로 기능이 작동하기 때문에 사용자 입장에서 번거롭게 여러번 입력하거나 커서를 이동할 필요 없이 모든 동작을 완료할 수 있습니다.

 

이러한 장점들이 있기 때문에 React Select 라이브러리를 사용하여 기능을 구현하게 되었습니다.  

 


구현하고자 하는 기능

1. 태그 검색

2. 태그 추가 ( 기존에 있는 태그 추가)

3. 태그 생성 ( 기존에 없던 태그 생성)

 

세부적인 기능 정리

태그 추가와 관련된 사항 : 태그는 한번에 하나만 추가 가능하나 / 복수 선택 가능 여부

태그 생성과 관련된 사항 : 태그 생성은 한번에 하나만 가능 / 단 복수 선택이 가능하도록 할 경우 선택한 태그와 추가 생성한 태그가 함께 추가 될 수 있다.

 

확인해야 하는 사항

태그 생성 API 

태그 추가와 생성을 각각의 API로 진행되어야하며 태그와 태그타입 생성은 동시에 가능하다. (코드 다시 확인해보기)

태그가 생성되는 시점 : 신규 태그 생성하기를 누르는 순간 서버로 보낼건지, 최종적으로 태그를 추가할 때 태그 추가  POST를 보내기전에 신규 태그 POST를 먼저 보낼지 

후자를 선택 : 선택한 이유 => 불필요한 태그 생성 방지 ( 사용하지 않고 생성만 해둔 태그들이 많아지는 것을 피하고자)

 

이에 따른 추가적인 기능 정리

신규 태그 타입 생성 

신규 태그 타입만 생성할 수 없고 반드시 태그를 함께 생성해야 한다. (불필요한 태그타입 생성 방지)

신규 태그 생성

태그 검색 결과가 없을 경우 목록에 create '입력한 태그명'이 나타난다.

신규 태그 생성 시점은 최종적으로 태그 추가하기를 누른 후, 태그 추가 POST 이전에 신규 태그 생성 먼저 진행되도록

 

 


구현 과정

1. select box 생성

 

2. 태그 검색 기능

태그 목록 불러오기

 

3. 태그 추가 기능

선택된 태그 값 저장

 

4. 신규 태그 생성

신규 생성한 태그 값 따로 저장 => 신규 태그 생성 API 따로 

 

5. 태그 추가 버튼

태그 추가 및 신규 태그 생성 동작이 이루어지도록

 

6. 태그 목록 업데이트 

태그 추가 후 자동으로 태그 목록 업데이트 되도록 async await (비동기처리 태그 목록과 관련한 글 추가로 작성하기)

 

 

1. select box 생성

 

 

2. 태그 검색 기능 

해당 기능을 개발하는 과정에서 아직 API 작업이 완료되지 않아 MockData로 작업을 진행했습니다.

아래와 같이 MockData를 state로 관리하고 해당 state를 options에 값으로 할당합니다.

const [tagStatus, setTagStatus] = useState<any>(initFilters.tagStatus)

const initFilters: FilterType = {
tagStatus: [
    { value: 1, label: 'public', checked: false },
    { value: 2, label: 'private', checked: false },
  ],
}

 

아래의 이미지와 같이 'tag' 영역을 클릭하면 아래에 태그 목록이 나옵니다.

이때 텍스트를 입력하면 해당하는 태그를 검색해서 보여줍니다. 

태그 목록만 연결해두면 따로 검색 기능을 구현하지 않아도 라이브러리에서 기본으로 검색기능을 제공합니다.

 

3. 태그 추가 기능

태그 목록에서 태그를 선택하면 그 값을 저장해야합니다.

이후 서버로 해당하는 인플루언서의 정보와 함께 태그 정보를 전달합니다.

 음악이라는 태그를 선택하고 '태그 추가'를 눌렀을 때 저장되는 태그 정보를 콘솔로 찍어보면 아래와 같이 나옵니다.

value.와 label로 된 객체 형태로 서버에 저장됩니다. 

onChange 를 이용해 선택된 value값만 따로 저장할 수 있습니다.

newValue를 state로 관리합니다.

onChange={(newValue) => setTagTypeValue(newValue)}

 

이때 신규 생성 되는 value와 구분 할 수 있도록 각각의 state를 생성해줍니다.

const [tagTypeValue, setTagTypeValue] = useState<Option | null>()
const [newTagTypeValue, setNewTagTypeValue] = useState<Option | null>()

 

 

4. 신규 태그 생성

기존의 태그 목록에 없는 태그를 사용자가 검색할 경우 태그 생성 버튼이 목록에 나타나도록 하는 기능을 추가해 보겠습니다. React Select 라이브러리에서 옵션 추가 생성 기능을 지원하고 있습니다. 

추가 생성 버튼 목록에 표시하기

onCreateOption property를 추가해줍니다.

 

추가 생성된 태그 저장하기

onCreateOption 이 실행 될 때 handleCreate 함수가 실행 되도록 합니다.

handleCreate에 매개 변수로 event와 'tag'라는 string을 함께 넘겨 줍니다.

이때 event는 새로 생성되는 태그의 value입니다.

 

string 'tag'를 함께 넘겨주는 이유

태그 타입 생성과 태그 생성을 구분하기 위해서

 

아래의 코드에 대해 설명

createOption은 신규 태그를 기존의 태그 형식으로 저장하는 함수입니다.

label과 value 형태로 태그를 저장하도록 합니다.

handleCreate 함수에서는 매개변수를 createOption함수를 이용해 newOption으로 저장합니다.

그리고 type에 따라 각각의 state를 업데이트 해줍니다.

이후 서버에 신규 태그 및 태그 타입 생성 요청시 필요한 데이터를 따로 관리합니다.

태그의 경우 복수 선택이 가능하고, 다수의 신규 태그를 동시에 생성할 수 있어 배열로 관리합니다. 

 

 

[ 추가적인 기능 ]

태그 복수 선택

복수 선택 기능을 사용하려면  isMulti property를 추가해야합니다.

      <CreatableSelect
        options={campaigns}
        isMulti
        onChange={(newValue) => setTagValue(newValue)}
        value={tagValue}
        onCreateOption={(e) => handleCreate(e, 'tag')}
        placeholder='tag'
      />

 

신규 생성 버튼 위치 조정

createOptionPosition property를 이용해 신규 생성 버튼을 목록 상단으로 배치합니다.

createOptionPosition={'first'}

신규 생성 버튼을 상단으로 배치하는 이유

기존에 태그 목록에 비슷한 이름의 태그가 많을 경우 스크롤이 생겨 신규 생성 버튼이 바로 보이지 않습니다.

태그를 검색함으로써 사용자가 신규 태그를 생성할 수 있음을 바로 알 수 있도록 상단으로 위치를 지정해줍니다.

 

5. 태그 추가 버튼

신규 생성 하기 버튼을 누르면 태그 영역에 새로운 태그가 추가됩니다.

하지만 이 단계에서 실제로 서버 새로운 태그가 생성되진 않았습니다.

 

기능 구현 전 정리한 사항들을 다시 보면

1. 신규 태그 타입만 생성할 수 없고 반드시 태그를 함께 생성해야 한다. (불필요한 태그타입 생성 방지)

2. 신규 태그 생성 시점은 최종적으로 태그 추가하기를 누른 후, 태그 추가 POST 이전에 신규 태그 생성 먼저 진행되도록 한다.

따라서 "태그 추가" 버튼을 눌렀을 때 신규 태그 생성 요청을 서버에 보내고, 그 후 태그 추가 요청을 보내도록 구현해야 합니다.

 

하지만 태그 생성과 관련된 기능을 팀원이 진행하기로 되어있어 추후 팀원이 API 연결을 진행하였습니다. 

저는 우선 태그 생성을 위한 데이터 저장과 태그 추가 버튼에 태그 목록(임시) 생성이 되도록하는 기능까지만 구현했습니다.

태그 추가 버튼을 클릭 하면 우선 태그 타입과 태그 값이 있는지 확인하고 선택된 값이 없을 경우 alert를 띄우도록 했습니다.

그리고 tagList에 tagValue를 저장해 추가된 태그 목록을 생성하였습니다.

( 이 목록은 임시이며 실제로는 서버에서 태그 리스트를 재호출하여 기능을 구현하였습니다.) 

 

이후 태그 추가가 이루어지고 나면 태그 선택 박스 전체를 리셋하여 처음의 상태로 돌려줍니다.

이 과정을 생략할 경우, 이전의 선택값이 그대로 select box에 남게 됩니다.

 

 

결과


어려웠던 점

기존의 방식보다훨씬 효율적으로 태그 검색 및 선택, 신규 태그 생성이 가능하다는 점에서 성공적인 도전이었습니다.

 

어려웠던 점

기획이 완전히 나오지 않은 상태라 어떤 경우라도 바로 대입이 가능하도록 여러가지 상황들을 고려하여 기능을 구현해야 했고, 코드를 작성하기에 앞서 그부분들을 정리하고 검증하는 과정이 어려웠습니다.

기능을 끝까지 구현하는 것이 아니라 다음 단계에서 동료가 더 쉽게 작업 할 수 있도록 하는 것이라 여러가지로 신경 써야하는 부분들이 많았습니다. 

특히 동료와 동시에 하나의 기능을 작업하고 있었기 때문에 계속해서 소통해야 했고 그 과정에서 신경쓰고 고려해야 할 사항들이 많았습니다.

 

해결 과정과 결과

문서로 기능들을 정리하며 동료와 계속해서 소통하려고 노력했습니다.

라이브러리에 대한 이해가 없는 동료를 위해 관련 자료와 함께 작성한 코드에 대한 설명을 함께 공유 했습니다.

실제 기능에서는 필요하지 않았던 태그 목록을 배열(임시)로 따로 만들어

동료가 전체 흐름을 이해하고 코드를 수정하기 쉽도록 했습니다.

 또한 어떤 기능들인지 동료가 쉽게 알아볼 수 있도록 직관적으로 코드를 작성하고,

컴포넌트로 개발해 바로 적용해 볼 수 있도록 했습니다.

이를 통해 어려움을 겪고 있던 동료는 예정된 일정대로 기능을 구현 할 수 있었습니다. 

 

 

어려웠던 점

그리고 타입 스크립트로 처음 작업을 진행했더니 타입 지정하는 부분에서 에러가 발생하여 시간이 더 소요되었습니다.

그리고 이후의 개발 과정에서 서버에서 보내는 데이터 형식에 수정 사항이 생기면서 타입 에러가 지속적으로 발생했습니다.

태그 생성 외 추가로 진행 했던 태그 수정 및 삭제, 태그 목록 생성 기능을 구현할 때 가장 많은 시간을 소요한 부분이기도 했습니다.

 

해결 과정과 결과

WBS를 활용하여 백엔드 동료와 적극적으로 소통하고 API 연결 전 체크 리스트를 작성하여 각자 기능에 대한 검증을 한번 더 진행했습니다. 그리고 데이터 타입들을 따로 관리하여 태그 타입에 따른 오류를 해결 하였습니다.

그 결과 실제 태그 수정, 삭제, 목록 호출에 대한 API 연결을 하루만에 다 완료하고

예정된 일정보다 앞서 기능 구현을 완료 하였습니다. 

 

 

배운점

이 기능을 개발하며 어느때보다 활발하게 동료들과 의사소통을 하였고, 주체적으로 기능을 기획하고 개발할 수 있었습니다.

각각의 페이지를 나눠서 작업 할 때에도 merge를 하면 발생하는 여러 오류들로 고생했던 경험이 있습니다.

이번에는 하나의 기능을 동시에 작업하다보니 그때보다 더 많은 문제들을 마주해야했습니다.

그리고 그 과정에서 내가 당연하다 생각하는 것도 동료는 모를 수 있고, 서로 생각하는 컨벤션이 다를 수 있다는 것을 배웠습니다.

초기 기획 단계에서 개발을 진행하며 정해진것이 없어 개발 과정에서 계속해서 협의하여 결정하는 사항들이 많았습니다.

그때마다 동료들과 소통하며 어떤 방식이 더 효율적이고 효과적인지 몸소 느낄 수 있었습니다.

WBS는 물론 기능 정리 문서를 따로 만들어 관리하였더니

계속해서 변경되는 기능들에 대한 내용들을 헷갈리지 않고 개발을 진행 할 수 있었습니다.

동료와 소통 할 때에도 말로만 소통하기보다는 문서를 기반으로 소통하니 훨씬 이해도가 높아지고 시간이 절약 되었습니다.

 

 

 

 

 

728x90