React - 타이틀 컴포넌트, 레이아웃 UI

김명원·2025년 1월 8일
1

learnReact

목록 보기
15/26

타이틀 컴포넌트

실습 - <Main />


  • src/components/Main.jsx

    function Main({ children }) {
      return <main className="container mx-auto px-4 py-16">{children}</main>;
    }
    
    export default Main;

    설명:

    • 목적: Main 컴포넌트는 애플리케이션의 주요 콘텐츠를 감싸는 레이아웃 컴포넌트입니다.
    • 구성:
      • children 프로퍼티를 통해 부모 컴포넌트로부터 전달된 자식 요소들을 렌더링합니다.
      • Tailwind CSS 클래스를 사용하여 중앙 정렬(mx-auto), 좌우 패딩(px-4), 상하 패딩(py-16)을 적용하여 일관된 레이아웃을 유지합니다.
    • 장점:
      • 재사용성: 여러 페이지에서 동일한 레이아웃을 손쉽게 적용할 수 있습니다.
      • 유지보수 용이: 레이아웃 변경 시 Main 컴포넌트만 수정하면 전체 애플리케이션에 반영됩니다.

  • src/App.jsx

    import { Outlet } from 'react-router-dom';
    import Header from './components/Header';
    import Main from './components/Main';
    
    function App() {
      return (
        <>
          <Header />
          <Main>
            <Outlet />
          </Main>
        </>
      );
    }
    
    export default App;

    설명:

    • 구성:
      • Header 컴포넌트를 상단에 배치하여 모든 페이지에서 공통으로 표시되는 헤더를 제공합니다.
      • Main 컴포넌트로 주요 콘텐츠 영역을 감싸며, 그 안에 Outlet을 배치하여 라우트에 따른 자식 컴포넌트를 렌더링합니다.
    • 장점:
      • 구조화: 헤더와 메인 콘텐츠를 명확히 분리하여 코드의 가독성을 높입니다.
      • 라우팅 통합: Outlet을 통해 React Router의 라우팅 기능을 원활하게 통합할 수 있습니다.

실습 - 타이틀


CanvasTitle 마크업

  • src/components/CanvasTitle.jsx

    import { FaEdit } from 'react-icons/fa';
    
    function CanvasTitle() {
      return (
        <div className="flex items-center justify-center mb-10">
          <h1 className="text-4xl font-bold text-center">Lean Canvas</h1>
          <button
            className="ml-2 p-2 bg-yellow-500 text-white rounded-full hover:bg-yellow-600 transition duration-300 ease-in-out focus:outline-none focus:ring-2 focus:ring-yellow-500 focus:ring-opacity-50"
            aria-label="Edit title"
          >
            <FaEdit />
          </button>
        </div>
      );
    }
    
    export default CanvasTitle;

    설명:

    • 목적: CanvasTitle 컴포넌트는 애플리케이션의 타이틀을 표시하고, 타이틀을 편집할 수 있는 버튼을 제공합니다.
    • 구성:
      • h1 태그를 사용하여 "Lean Canvas"라는 타이틀을 중앙에 크게 표시합니다.
      • FaEdit 아이콘을 포함한 버튼을 추가하여 사용자가 타이틀을 편집할 수 있는 인터페이스를 제공합니다.
      • Tailwind CSS 클래스를 활용하여 레이아웃(flex, items-center, justify-center), 마진(mb-10), 타이틀 스타일(text-4xl, font-bold), 버튼 스타일(bg-yellow-500, rounded-full 등)을 적용했습니다.
    • 장점:
      • 시각적 강조: 큰 타이틀과 눈에 띄는 편집 버튼을 통해 사용자가 쉽게 타이틀을 인식하고 편집할 수 있습니다.
      • 반응형 디자인: Tailwind CSS의 유틸리티 클래스를 사용하여 다양한 화면 크기에서도 일관된 레이아웃을 유지합니다.
      • 접근성: aria-label 속성을 통해 버튼의 목적을 명확히 전달하여 스크린 리더 사용자에게 유용합니다.

CanvasTitle 컴포넌트

  • src/components/CanvasTitle.jsx

    import { useState } from 'react';
    import { FaCheck, FaEdit } from 'react-icons/fa';
    
    function CanvasTitle() {
      const [title, setTitle] = useState('Lean Canvas');
      const [editedTitle, setEditedTitle] = useState(title);
      const [isEditing, setIsEditing] = useState(false);
    
      const handleEditTitle = () => {
        setIsEditing(true);
      };
    
      const handleTitleChange = e => {
        setEditedTitle(e.target.value);
      };
    
      const handleTitleSubmit = () => {
        setTitle(editedTitle);
        setIsEditing(false);
      };
    
      return (
        <div className="flex items-center justify-center mb-10">
          {isEditing ? (
            <div className="flex items-center">
              <input
                type="text"
                value={editedTitle}
                onChange={handleTitleChange}
                className="text-4xl font-bold text-center text-blue-600 bg-transparent border-b-2 border-blue-600 focus:outline-none"
              />
              <button
                onClick={handleTitleSubmit}
                className="ml-2 p-2 bg-green-500 text-white rounded-full hover:bg-green-600 transition duration-300 ease-in-out focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-opacity-50"
                aria-label="Save title"
              >
                <FaCheck />
              </button>
            </div>
          ) : (
            <h1 className="text-4xl font-bold text-center">{title}</h1>
          )}
          {!isEditing && (
            <button
              onClick={handleEditTitle}
              className="ml-2 p-2 bg-yellow-500 text-white rounded-full hover:bg-yellow-600 transition duration-300 ease-in-out focus:outline-none focus:ring-2 focus:ring-yellow-500 focus:ring-opacity-50"
              aria-label="Edit title"
            >
              <FaEdit />
            </button>
          )}
        </div>
      );
    }
    
    export default CanvasTitle;

    설명:

    • 목적: CanvasTitle 컴포넌트는 타이틀을 표시할 뿐만 아니라, 사용자가 타이틀을 편집할 수 있는 기능을 제공합니다.
    • 구성:
      • 상태 관리:
        • title: 현재 타이틀을 저장하는 상태.
        • editedTitle: 사용자가 입력한 새로운 타이틀을 임시로 저장하는 상태.
        • isEditing: 편집 모드 여부를 나타내는 상태.
      • 이벤트 핸들러:
        • handleEditTitle: 편집 모드를 활성화합니다.
        • handleTitleChange: 입력 필드의 값을 업데이트합니다.
        • handleTitleSubmit: 수정된 타이틀을 title 상태에 반영하고 편집 모드를 종료합니다.
      • 조건부 렌더링:
        • isEditingtrue일 때: 입력 필드와 저장 버튼을 표시하여 사용자가 타이틀을 수정할 수 있게 합니다.
        • isEditingfalse일 때: 타이틀 텍스트와 편집 버튼을 표시합니다.
      • 스타일링:
        • Tailwind CSS 클래스를 사용하여 레이아웃(flex, items-center, justify-center), 타이틀 및 버튼의 스타일을 적용했습니다.
        • 입력 필드와 버튼에는 포커스 및 호버 상태에 대한 스타일링을 추가하여 사용자 인터랙션을 강화했습니다.
    • 장점:
      • 동적 UI: 사용자 상호작용에 따라 UI가 동적으로 변하여 편리한 편집 경험을 제공합니다.
      • 상태 관리: React의 useState 훅을 활용하여 컴포넌트의 상태를 효과적으로 관리합니다.
      • 재사용성: 다른 페이지나 컴포넌트에서도 동일한 타이틀 편집 기능을 손쉽게 사용할 수 있습니다.
      • 접근성: aria-label 속성을 통해 버튼의 목적을 명확히 전달하여 스크린 리더 사용자에게 유용합니다.

전체적인 구조와 동작 방식

  • 컴포넌트 분리:

    • UI를 여러 개의 작은 컴포넌트로 분리하여 각 컴포넌트가 하나의 역할을 담당하도록 설계했습니다.
      • Main: 주요 콘텐츠 영역을 감싸는 레이아웃 컴포넌트.
      • CanvasTitle: 타이틀을 표시하고 편집할 수 있는 기능을 제공.
      • 기타 컴포넌트(CanvasItem, CanvasList, SearchBar, ViewToggle)도 각 기능에 따라 분리되어 코드의 재사용성과 유지보수성을 높였습니다.
  • 상태 관리:

    • Home 페이지에서 searchText, isGridView, dummyData 등의 상태를 관리하여 자식 컴포넌트에 전달합니다.
    • 상태 변경 시 React가 자동으로 UI를 업데이트하여 사용자에게 실시간 피드백을 제공합니다.
  • 반응형 디자인:

    • Tailwind CSS의 유틸리티 클래스를 사용하여 다양한 화면 크기에 대응하는 레이아웃을 구현했습니다.
    • 예를 들어, sm:flex-row 클래스를 사용하여 작은 화면에서는 세로로, 큰 화면에서는 가로로 레이아웃을 변경합니다.
  • 접근성:

    • aria-label 속성을 사용하여 버튼과 입력 필드의 목적을 명확히 전달했습니다.
    • 시맨틱 HTML 요소와 적절한 ARIA 속성을 사용하여 모든 사용자가 접근 가능한 UI를 구현했습니다.
  • 애니메이션과 트랜지션:

    • Tailwind CSS의 transition-transform, duration-300, hover:scale-105 등을 활용하여 사용자 인터랙션 시 부드러운 애니메이션 효과를 추가했습니다.
  • 아이콘 사용:

    • react-icons 라이브러리를 사용하여 시각적인 아이콘을 추가함으로써 UI의 직관성과 미적 요소를 강화했습니다.

결론

이번 실습에서는 타이틀 컴포넌트를 구현하여 애플리케이션의 핵심 타이틀을 효과적으로 관리할 수 있게 했습니다. Main 컴포넌트를 통해 일관된 레이아웃을 유지하며, CanvasTitle 컴포넌트는 사용자에게 직관적인 편집 기능을 제공했습니다. 컴포넌트 분리를 통해 코드의 재사용성과 유지보수성을 높였으며, Tailwind CSS와 React Icons를 활용하여 깔끔하고 반응형인 사용자 인터페이스를 구현했습니다.


레이아웃 UI

실습


1. src/components/CanvasCard.jsx

import { FaPlus } from 'react-icons/fa';

function CanvasCard({ title, isSubtitle = false }) {
  return (
    <div className="row-span-1 bg-white min-h-48 border border-collapse border-gray-300">
      <div
        className={`${isSubtitle === false && 'bg-gray-100 border-b border-b-gray-300'} flex items-start justify-between px-3 py-2`}
      >
        <h3 className={`${isSubtitle === false && 'font-bold'} `}>{title}</h3>
        <button className="bg-blue-400 text-white p-1.5 text-xs rounded-md">
          <FaPlus />
        </button>
      </div>
      <div className="space-y-3 min-h-32 p-3">memo..</div>
    </div>
  );
}

export default CanvasCard;

설명:

  • 목적: CanvasCard 컴포넌트는 린캔버스의 각 섹션을 카드 형태로 표시합니다.
  • 구성 요소:
    • Props:
      • title: 카드의 제목을 설정합니다.
      • isSubtitle (기본값 false): 해당 섹션이 부제목인지 여부를 결정하여 스타일을 다르게 적용합니다.
    • 레이아웃:
      • 카드 전체는 흰색 배경(bg-white)과 회색 경계선(border-gray-300)으로 스타일링되어 있습니다.
      • 헤더 부분은 flex 레이아웃을 사용하여 제목과 추가 버튼을 양쪽 끝에 배치합니다.
      • isSubtitlefalse일 경우, 헤더에 회색 배경과 하단 경계선(bg-gray-100 border-b-gray-300)이 적용되고, 제목에 굵은 글씨(font-bold)가 적용됩니다.
      • 추가 버튼은 파란색 배경(bg-blue-400)과 흰색 텍스트(text-white)로 스타일링되어 있으며, 클릭 시 새로운 항목을 추가할 수 있는 기능을 암시합니다.
    • 컨텐츠 영역:
      • memo.. 텍스트가 있는 공간은 여유 공간(min-h-32)과 패딩(p-3)을 통해 내용이 추가될 때 깔끔하게 표시됩니다.
  • 장점:
    • 재사용성: 다양한 린캔버스 섹션에 동일한 CanvasCard 컴포넌트를 재사용할 수 있어 코드의 중복을 줄입니다.
    • 유연성: isSubtitle prop을 통해 섹션의 중요도에 따라 스타일을 동적으로 변경할 수 있습니다.
    • 가독성 향상: 컴포넌트 분리를 통해 각 카드의 구조와 스타일을 명확히 구분할 수 있습니다.

2. src/components/LeanCanvas.jsx

import CanvasCard from './CanvasCard';

function LeanCanvas() {
  return (
    <div className="border-4 border-black">
      <div className="grid grid-cols-5">
        <CanvasCard title={'1. 문제'} />
        <CanvasCard title={'4. 해결안'} />
        <CanvasCard title={'3. 가치제안'} />
        <CanvasCard title={'5. 경쟁우위'} />
        <CanvasCard title={'2. 목표 고객'} />
        <CanvasCard title={'기존 대안'} isSubtitle />
        <CanvasCard title={'8. 핵심지표'} />
        <CanvasCard title={'상위개념'} isSubtitle />
        <CanvasCard title={'9. 고객 경로'} />
        <CanvasCard title={'얼리 어답터'} isSubtitle />
      </div>
      <div className="grid grid-cols-2">
        <CanvasCard title={'7. 비용 구조'} />
        <CanvasCard title={'6. 수익 흐름'} />
      </div>
    </div>
  );
}

export default LeanCanvas;

설명:

  • 목적: LeanCanvas 컴포넌트는 린캔버스의 전체 레이아웃을 그리드 시스템을 활용하여 구성합니다.
  • 구성 요소:
    • 레이아웃:
      • 전체 린캔버스는 두 개의 그리드 섹션으로 나뉩니다.
        • 첫 번째 그리드는 5열(grid-cols-5)로 구성되어 다양한 린캔버스 섹션을 배치합니다.
        • 두 번째 그리드는 2열(grid-cols-2)로 구성되어 추가적인 섹션을 배치합니다.
    • CanvasCard 사용:
      • 각 린캔버스 섹션은 CanvasCard 컴포넌트를 사용하여 일관된 스타일로 표시됩니다.
      • isSubtitle prop을 통해 특정 섹션의 스타일을 조정하여 중요한 섹션과 보조 섹션을 시각적으로 구분합니다.
  • 장점:
    • 구조화: 그리드 레이아웃을 사용하여 린캔버스의 각 섹션을 체계적으로 배치할 수 있습니다.
    • 재사용성: CanvasCard 컴포넌트를 활용하여 섹션 추가 및 변경이 용이합니다.
    • 유지보수성: 레이아웃 변경 시 CanvasCard의 props만 조정하면 되므로 코드의 유지보수가 간편합니다.

3. src/pages/CanvasDetail.jsx

import CanvasTitle from '../components/CanvasTitle';
import LeanCanvas from '../components/LeanCanvas';

function CanvasDetail() {
  return (
    <div>
      <CanvasTitle />
      <LeanCanvas />
    </div>
  );
}

export default CanvasDetail;

설명:

  • 목적: CanvasDetail 페이지는 개별 린캔버스의 상세 정보를 표시하는 페이지로, 타이틀과 린캔버스 레이아웃을 포함합니다.
  • 구성 요소:
    • CanvasTitle:
      • 린캔버스의 제목을 표시하며, 편집 가능한 기능을 제공합니다.
      • 사용자가 타이틀을 클릭하여 수정할 수 있는 인터페이스를 제공합니다.
    • LeanCanvas:
      • 린캔버스의 각 섹션을 그리드 레이아웃으로 표시합니다.
      • CanvasCard 컴포넌트를 활용하여 각 섹션을 일관된 스타일로 렌더링합니다.
  • 장점:
    • 명확한 구조: 타이틀과 린캔버스 레이아웃을 별도의 컴포넌트로 분리하여 페이지의 구조를 명확히 합니다.
    • 재사용성: CanvasTitleLeanCanvas 컴포넌트를 다른 페이지에서도 재사용할 수 있어 코드의 효율성을 높입니다.
    • 유지보수성: 각 컴포넌트가 독립적으로 관리되므로 개별 기능을 수정하거나 확장하기 용이합니다.

전체적인 구조와 동작 방식

  • 컴포넌트 분리:

    • UI를 여러 개의 작은 컴포넌트로 분리하여 각 컴포넌트가 하나의 역할을 담당하도록 설계했습니다.
      • CanvasCard: 린캔버스의 개별 섹션을 카드 형태로 표시합니다.
      • LeanCanvas: 린캔버스의 전체 레이아웃을 그리드 시스템으로 구성합니다.
      • CanvasTitle: 린캔버스의 타이틀을 표시하고 편집할 수 있는 기능을 제공합니다.
      • 기타 컴포넌트(CanvasItem, CanvasList, SearchBar, ViewToggle, Main, Header)도 각 기능에 따라 분리되어 코드의 재사용성과 유지보수성을 높였습니다.
  • 상태 관리:

    • Home 페이지에서 searchText, isGridView, dummyData 등의 상태를 관리하여 자식 컴포넌트에 전달합니다.
    • 삭제 기능을 구현하기 위해 handleDeleteItem 함수를 통해 dummyData 상태를 업데이트합니다.
  • 반응형 디자인:

    • Tailwind CSS의 유틸리티 클래스를 사용하여 다양한 화면 크기에 대응하는 레이아웃을 구현했습니다.
    • 예를 들어, grid-cols-5grid-cols-2 클래스를 사용하여 그리드의 열 수를 조정하고, sm:flex-row 클래스를 통해 작은 화면에서는 세로로, 큰 화면에서는 가로로 레이아웃을 변경합니다.
  • 접근성:

    • aria-label 속성을 사용하여 버튼과 입력 필드의 목적을 명확히 전달했습니다. 이는 스크린 리더 사용자에게 유용합니다.
    • 시맨틱 HTML 요소와 적절한 ARIA 속성을 사용하여 모든 사용자가 접근 가능한 UI를 구현했습니다.
  • 애니메이션과 트랜지션:

    • Tailwind CSS의 transition-transform, duration-300, hover:scale-105 등을 활용하여 사용자 인터랙션 시 부드러운 애니메이션 효과를 추가했습니다.
    • 삭제 버튼과 추가 버튼에 호버 효과를 적용하여 시각적인 피드백을 제공합니다.
  • 아이콘 사용:

    • react-icons 라이브러리를 사용하여 시각적인 아이콘을 추가함으로써 UI의 직관성과 미적 요소를 강화했습니다.
    • 예를 들어, FaPlus 아이콘을 사용하여 추가 기능을, FaEdit 아이콘을 사용하여 편집 기능을 직관적으로 표시했습니다.

결론

이번 실습에서는 레이아웃 UI를 구현하여 린캔버스의 각 섹션을 체계적으로 관리하고 표시할 수 있는 구조를 만들었습니다. 컴포넌트 분리를 통해 코드의 재사용성과 유지보수성을 높였으며, Tailwind CSS와 React Icons를 활용하여 깔끔하고 반응형인 사용자 인터페이스를 구현했습니다. 또한, 상태 관리를 통해 동적인 UI 업데이트와 사용자 상호작용을 효과적으로 처리했습니다.


profile
개발자가 되고 싶은 정치학도생의 기술 블로그

0개의 댓글