본문 바로가기

Development

[UI 만들기] 1. Accordion

 

 

  프로젝트를 진행하며 아쉬웠던 점 중 하나가 UI를 제작하는 부분이었다. 아직 경험이 부족하다 보니 UI를 만들기는 하는데, 이게 좋은 UI인지 이렇게 하는게 성능상 문제는 없는지와 같은 지식이 부족했다. UI 역시 나름 어느정도는 정석에 가까운 최적화된 개발 방식들이 있다고 생각한다. 그래서 좀 더 좋은 프론트 개발자가 되기 위해서 UI를 제작하는 방법들을 하나씩 공부해보고자 한다.

  아코디언은 정말 많이 사용되는 UI중 하나이다. 아코디언을 첫번째로 꼽은 이유는 사실 이번에 개발했던 UI중 가장 아쉬운 UI이기 때문이다. 아코디언은 기본적으로 열고 닫기 기능을 포함한다. 여기서 중요한 것은 열고 닫으면서 특정 상태를 변경해야 하고, 하나의 컴포넌트로 만들되 각각 독립적으로 제어가 되야 한다.

import React, { useState } from 'react';

type AccordionProps = {
  title: string;
  content: string;
};

const Accordion: React.FC<AccodionProps> = ({ title, content }) => {
  const [isOpen, setIsOpen] = useState(false);
    
  const handleClick = () => {
    setIsOpen(!isOpen);
  }
    
  return (
    <div className="accordion">
      <div className="accordion-header" onClick={handleClick}>
        <h3>{title}</h3>
        <span>{isOpen ? '-' : '+'}</span>
      </div>
      {isOpen && <div className="accordion-content">{content}</div>}
    </div>
  )
};

export default Accordion;

먼저, typescript를 사용했기 때문에 title과 content의 타입을 정의할 AccordionProps 인터페이스를 정의한다. 그리고 아코디언의 열기 닫기 상태를 제어하는 isOpen state를 정의한다. 또 아코디언 헤더를 클릭할 때 호출되는 handleClick 함수도 정의한다. 이 함수는 isOpen 상태를 토글한다.

  이렇게 컴포넌트로 만들어서 이제 화면에 각각 이 컴포넌트를 넣을 수 있다.

import React from 'react';
import Accordion from './Accodion';

const App: React.FC = () => {
	return (
    	<div>
        	<Accordion title="Section 1" content="Content 1" />
            <Accordion title="Section 2" content="Content 2" />
            <Accordion title="Section 3" content="Content 3" />
        </div>
    )
}

export default App;

이렇게 사용하면 각각 따로 열고 닫기가 제어되는 3개의 다른 아코디언을 제공할 수 있다.

 

  문제는 이 아코디언에 열리고 닫힘에 따라 다른 상태가 변해야하는 경우가 자주 발생할 수 있다는 것이다. 그 때는 부모 컴포넌트로부터 아코디언들의 상태와 유니크값을 받아와야한다.

import React, { useState } from 'react';

type AccordionProps = {
  title: string;
  content: string;
  index: number;
  accordions: { [key: number]: boolean };
  setAccordions: React.Dispatch<React.SetStateAction<{[key: number]: boolean}>>
};

const Accordion: React.FC<AccordionProps> = ({ title, content, index, accordions, setAccordions }) => {
  const [isOpen, setIsOpen] = useState(accordions[index]);
  
  const handleClick = () => {
    setIsOpen(!isOpen)
    setAccordions({ ...accordions, [index]: !isOpen });
  };
  
  return (
    <div className="accordion">
      <div className="accordion-header" onClick={handleClick}>
        <h3>{title}</h3>
        <span>{isOpen ? '-' : '+'}</span>
      </div>
      {isOpen && <div className="accordion-content">{content}</div>}
    </div>
  )
}

export default Accordion;

먼저 accordions와 setAccordions props를 추가했다. accordions props는 아코디언의 열기 닫기 상태를 가지는 개체이고 setAccordions는 이 객체를 업데이트하는 함수이다. 또 index props를 사용해서 아코디언 객체에서 inOpen 상태를 사용하도록 했다. 결국 index를 키로 isOpen을 값으로 사용하게 된다. 그래서 handleClick 함수가 호출되면 isOpen 상태를 토글하고 setAccordions 함수를 사용하여 accordions 객체를 업데이트한다. 

import React, { useState } from 'react';
import Accordion from './Accordion';

const App: React.FC = () => {
  const [accordions, setAccordions] = useState<{ [key: number]: boolean }>({});
  
  return (
    <div>
      <Accordion title="Section 1" content="Content 1" index={1} accordions={accordions} setAccordions={setAccordions} />
      <Accordion title="Section 2" content="Content 2" index={2} accordions={accordions} setAccordions={setAccordions} />
      <Accordion title="Section 3" content="Content 3" index={3} accordions={accordions} setAccordions={setAccordions} />
    </div>
  )
}

export default App;

이렇게 하면 상태를 독립적으로 변경할 수 있는 여러 아코디언을 가질 수 있고 각 아코디언이 열린 상태에 따라 앱의 상태를 업데이트할 수 있다.

'Development' 카테고리의 다른 글

[UI 만들기] 4. Popper  (0) 2023.04.05
[UI 만들기] 3. Top Navbar  (0) 2023.04.04
[UI 만들기] 2. Modal  (0) 2023.03.27
chat GPT가 말하는 프론트엔드 개발자의 전망  (0) 2023.03.13