React - 린캔버스 수정 2

김명원·2025년 1월 12일
0

learnReact

목록 보기
21/26

린캔버스 수정 2 🖋️✨

이번 포스트에서는 린캔버스 애플리케이션의 사용자 경험을 더욱 향상시키기 위해 노트 추가 및 삭제 기능을 구현하고, 한글 입력 이슈를 해결하는 과정을 다룹니다. 각 파일별로 코드 변경 사항을 상세히 설명하며, 이러한 변경이 애플리케이션에 미치는 영향을 분석하겠습니다.


src/components/Note.jsx 수정

노트 삭제 기능 개선

// ... 생략 ...
<button
  aria-label="Close Note"
  className="text-gray-700"
  onClick={e => {
    e.stopPropagation();
    onRemoveNote(id);
  }}
>
  <AiOutlineClose size={20} />
</button>
// ... 생략 ...

코드 설명:

  • 이벤트 전파 방지 (e.stopPropagation()):

    • 변경 전: onClick={() => onRemoveNote(id)}
    • 변경 후: onClick={e => { e.stopPropagation(); onRemoveNote(id); }}

    노트 삭제 버튼을 클릭할 때, 버튼의 클릭 이벤트가 부모 요소로 전파되는 것을 방지하기 위해 e.stopPropagation()을 추가했습니다. 이는 사용자가 노트를 삭제할 때 의도치 않게 노트 전체가 편집 모드로 전환되는 현상을 방지합니다. 예를 들어, 노트가 클릭되면 편집 모드로 전환되는데, 삭제 버튼을 클릭할 때 이 이벤트가 부모로 전파되어 노트가 동시에 편집 모드로 전환되는 것을 막습니다.

  • 노트 삭제 로직 (onRemoveNote(id)):

    • 노트 삭제 버튼을 클릭하면 해당 노트의 id를 인자로 onRemoveNote 함수를 호출하여 노트를 삭제합니다. 이 함수는 상위 컴포넌트에서 관리되며, 삭제된 노트는 UI에서 즉시 제거됩니다.

추가 설명:

이 변경을 통해 사용자가 노트를 삭제할 때 보다 직관적이고 오류 없는 경험을 제공할 수 있게 되었습니다. 이벤트 전파를 중지함으로써 노트 삭제 시 불필요한 편집 모드 전환을 방지하고, 사용자 의도에 맞는 동작만을 수행하도록 했습니다.


🎨 src/components/LeanCanvas.jsx 수정

노트 관리 로직 강화

// ... 생략 ...
<CanvasCard
  title={'4. 해결안'}
  notes={canvas.solution.notes}
  onNotesChange={notes => handleNotesChange('solution', notes)}
/>
<CanvasCard
  title={'3. 가치제안'}
  notes={canvas.valueProposition.notes}
  onNotesChange={notes => handleNotesChange('valueProposition', notes)}
/>
<CanvasCard
  title={'5. 경쟁우위'}
  notes={canvas.unfairAdvantage.notes}
  onNotesChange={notes => handleNotesChange('unfairAdvantage', notes)}
/>
<CanvasCard
  title={'2. 목표 고객'}
  notes={canvas.customerSegments.notes}
  onNotesChange={notes => handleNotesChange('customerSegments', notes)}
/>
<CanvasCard
  title={'기존 대안'}
  isSubtitle
  notes={canvas.existingAlternatives.notes}
  onNotesChange={notes =>
    handleNotesChange('existingAlternatives', notes)
  }
/>
<CanvasCard
  title={'8. 핵심지표'}
  notes={canvas.keyMetrics.notes}
  onNotesChange={notes => handleNotesChange('keyMetrics', notes)}
/>
<CanvasCard
  title={'상위개념'}
  isSubtitle
  notes={canvas.highLevelConcept.notes}
  onNotesChange={notes => handleNotesChange('highLevelConcept', notes)}
/>
<CanvasCard
  title={'9. 고객 경로'}
  notes={canvas.channels.notes}
  onNotesChange={notes => handleNotesChange('channels', notes)}
/>
<CanvasCard
  title={'얼리 어답터'}
  isSubtitle
  notes={canvas.earlyAdopters.notes}
  onNotesChange={notes => handleNotesChange('earlyAdopters', notes)}
/>
<CanvasCard
  title={'7. 비용 구조'}
  notes={canvas.costStructure.notes}
  onNotesChange={notes => handleNotesChange('costStructure', notes)}
/>
<CanvasCard
  title={'6. 수익 흐름'}
  notes={canvas.revenueStreams.notes}
  onNotesChange={notes => handleNotesChange('revenueStreams', notes)}
/>
// ... 생략 ...

코드 설명:

  • 다양한 CanvasCard 컴포넌트 추가:

    • 각 섹션별로 CanvasCard 컴포넌트를 추가하여 린캔버스의 모든 섹션을 포괄적으로 관리할 수 있게 했습니다.
    • 예시:
      <CanvasCard
        title={'4. 해결안'}
        notes={canvas.solution.notes}
        onNotesChange={notes => handleNotesChange('solution', notes)}
      />
      • title: 섹션의 제목을 설정합니다.
      • notes: 해당 섹션의 노트 데이터를 전달합니다.
      • onNotesChange: 노트가 변경될 때 호출되는 함수로, 상위 컴포넌트(LeanCanvas)의 handleNotesChange 함수를 호출하여 섹션별로 노트 변경 사항을 처리합니다.
  • 섹션별 노트 변경 처리:

    • handleNotesChange 함수는 특정 섹션의 노트가 변경될 때 호출되어 전체 캔버스 데이터를 업데이트합니다.
    • 이는 각 섹션의 노트가 독립적으로 관리되면서도, 전체 캔버스 데이터와 일관성을 유지할 수 있도록 합니다.

추가 설명:

LeanCanvas 컴포넌트는 린캔버스의 각 섹션을 CanvasCard 컴포넌트로 분리하여 관리함으로써, 코드의 재사용성과 유지보수성을 크게 향상시켰습니다. 각 섹션별로 노트를 추가, 수정, 삭제할 수 있는 기능을 제공하여 사용자가 린캔버스를 보다 체계적으로 관리할 수 있게 되었습니다.


🗂️ src/components/CanvasCard.jsx 수정

노트 추가 및 삭제 기능 구현

import { v4 as uuidv4 } from 'uuid';
import { FaPlus } from 'react-icons/fa';
import Note from './Note';

function CanvasCard({ title, isSubtitle = false, notes = [], onNotesChange }) {
  const handleAddNote = () => {
    const newNote = {
      id: uuidv4(),
      content: '',
      color: '',
    };
    onNotesChange([...notes, newNote]);
  };

  const handleRemoveNote = id => {
    onNotesChange(notes.filter(note => note.id !== id));
  };

  const handleUpdateNote = (id, content, color) => {
    onNotesChange(
      notes.map(note => (note.id === id ? { ...note, content, color } : note)),
    );
  };

  return (
    <div className="row-span-1 bg-white min-h-48 border border-gray-300 p-4 rounded shadow">
      <h2 className={`text-xl font-semibold mb-4 ${isSubtitle ? 'text-gray-700' : 'text-black'}`}>
        {title}
      </h2>
      <div className="space-y-2">
        {notes.map(note => (
          <Note
            key={note.id}
            id={note.id}
            content={note.content}
            color={note.color}
            onRemoveNote={handleRemoveNote}
            onUpdateNote={handleUpdateNote}
          />
        ))}
        <button
          className="flex items-center justify-center w-full p-2 bg-green-500 text-white rounded hover:bg-green-600 transition"
          onClick={handleAddNote}
        >
          <FaPlus /> 추가
        </button>
      </div>
    </div>
  );
}

export default CanvasCard;

코드 설명:

  • UUID를 사용한 노트 ID 생성 (uuidv4()):

    • import { v4 as uuidv4 } from 'uuid';를 추가하여 각 노트에 고유한 id를 부여합니다.
    • 노트를 추가할 때 handleAddNote 함수는 uuidv4()를 사용하여 새로운 노트의 id를 생성하고, 기본 contentcolor를 설정합니다.
  • 노트 추가 (handleAddNote):

    • 사용자가 "추가" 버튼을 클릭하면 handleAddNote 함수가 호출됩니다.
    • 이 함수는 새로운 노트를 생성하고, 기존 노트 배열에 추가한 후 onNotesChange 함수를 통해 상위 컴포넌트에 전달합니다.
    • 이는 사용자가 자유롭게 노트를 추가할 수 있게 해주며, 새로운 노트는 기본 설정으로 초기화됩니다.
  • 노트 삭제 (handleRemoveNote):

    • 사용자가 노트를 삭제할 때 handleRemoveNote 함수가 호출됩니다.
    • 이 함수는 특정 id를 가진 노트를 필터링하여 제거한 후, 업데이트된 노트 배열을 onNotesChange 함수를 통해 상위 컴포넌트에 전달합니다.
    • 이는 사용자가 불필요한 노트를 손쉽게 제거할 수 있게 합니다.
  • 노트 업데이트 (handleUpdateNote):

    • 사용자가 노트의 내용을 수정하거나 색상을 변경할 때 handleUpdateNote 함수가 호출됩니다.
    • 이 함수는 해당 노트의 id를 찾아 새로운 contentcolor로 업데이트한 후, 전체 노트 배열을 onNotesChange 함수를 통해 상위 컴포넌트에 전달합니다.
    • 이는 노트의 실시간 업데이트를 가능하게 하여 데이터의 일관성을 유지합니다.
  • 스타일링 및 레이아웃:

    • row-span-1, bg-white, min-h-48, border, border-gray-300, p-4, rounded, shadow 등의 Tailwind CSS 클래스를 사용하여 카드의 시각적 스타일을 지정하고, 사용자에게 깔끔하고 직관적인 UI를 제공합니다.
  • 노트 렌더링 및 추가 버튼:

    • notes.map을 사용하여 각 노트를 Note 컴포넌트로 렌더링합니다.
    • "추가" 버튼을 통해 새로운 노트를 추가할 수 있는 기능을 제공합니다.

추가 설명:

CanvasCard 컴포넌트는 린캔버스의 각 섹션을 관리하는 핵심 요소로, 사용자가 노트를 자유롭게 추가, 수정, 삭제할 수 있도록 설계되었습니다. UUID를 사용하여 각 노트에 고유한 id를 부여함으로써, 노트 관리의 정확성과 신뢰성을 높였습니다. 또한, Tailwind CSS를 활용한 스타일링은 컴포넌트의 일관된 디자인을 유지하면서도 사용자에게 친숙한 인터페이스를 제공합니다.


🖌️ src/components/Note.jsx 수정

노트 추가 및 삭제 기능 구현

import { useEffect, useRef, useState } from 'react';
import { AiOutlineClose, AiOutlineCheck } from 'react-icons/ai';

const Note = ({
  id,
  content,
  color: initialColor,
  onUpdateNote,
  onRemoveNote,
}) => {
  const [localContent, setLocalContent] = useState(content);

  const colorOptions = [
    'bg-yellow-300',
    'bg-pink-300',
    'bg-blue-300',
    'bg-green-300',
  ];

  const [color, setColor] = useState(() => {
    if (initialColor) return initialColor;
    const randomIndex = Math.floor(Math.random() * colorOptions.length);
    return colorOptions[randomIndex];
  });

  const [isEditing, setIsEditing] = useState(false);

  const textareaRef = useRef(null);

  useEffect(() => {
    if (textareaRef.current) {
      textareaRef.current.style.height = 'auto';
      textareaRef.current.style.height =
        textareaRef.current.scrollHeight + 'px';
    }
  }, [content]);

  const handleContentChange = () => {
    onUpdateNote(id, localContent, color);
  };

  const handleColorChange = newColor => {
    setColor(newColor);
    onUpdateNote(id, content, newColor);
  };

  return (
    <div
      className={`p-4 ${color} relative max-h-[32rem] overflow-hidden`}
      onClick={() => setIsEditing(true)}
    >
      <div className="absolute top-2 right-2">
        {isEditing ? (
          <button
            aria-label="Check Note"
            className="text-gray-700"
            onClick={e => {
              e.stopPropagation();
              setIsEditing(false);
            }}
          >
            <AiOutlineCheck size={20} />
          </button>
        ) : (
          <button
            aria-label="Close Note"
            className="text-gray-700"
            onClick={e => {
              e.stopPropagation();
              onRemoveNote(id);
            }}
          >
            <AiOutlineClose size={20} />
          </button>
        )}
      </div>
      <textarea
        ref={textareaRef}
        value={localContent}
        onChange={e => setLocalContent(e.target.value)}
        onBlur={handleContentChange}
        className={`w-full h-full bg-transparent resize-none border-none focus:outline-none text-gray-900 overflow-hidden`}
        aria-label="Edit Note"
        placeholder="메모를 작성하세요."
        style={{ height: 'auto', minHeight: '8rem' }}
        readOnly={!isEditing}
      />
      {isEditing && (
        <div className="flex space-x-2">
          {colorOptions.map((option, index) => (
            <button
              key={index}
              className={`w-6 h-6 rounded-full cursor-pointer outline outline-gray-50 ${option}`}
              onClick={() => handleColorChange(option)}
              aria-label={`Change color to ${option}`}
            />
          ))}
        </div>
      )}
    </div>
  );
};

export default Note;

코드 설명:

  • 로컬 상태 관리 (useState):

    • localContent: 노트의 현재 내용을 로컬 상태로 관리하여 사용자가 입력하는 동안 실시간으로 업데이트됩니다.
    • color: 노트의 배경색을 관리합니다. 초기 값은 initialColor로 설정되며, 설정되지 않은 경우 랜덤하게 선택됩니다.
    • isEditing: 노트가 현재 편집 모드인지 여부를 관리합니다.
  • 참조 관리 (useRef):

    • textareaRef: 텍스트 영역의 DOM 요소에 접근하여 자동 높이 조절 기능을 구현합니다.
  • 자동 높이 조절 (useEffect):

    • useEffect 훅을 사용하여 content가 변경될 때마다 텍스트 영역의 높이를 자동으로 조절합니다. 이는 사용자가 노트의 내용을 입력할 때 텍스트 영역이 자동으로 확장되어 스크롤 없이 모든 내용을 볼 수 있게 합니다.
  • 내용 변경 처리 (handleContentChange):

    • 사용자가 텍스트 영역에 내용을 입력하고 포커스를 잃을 때 (onBlur 이벤트) handleContentChange 함수가 호출되어 상위 컴포넌트에 변경된 내용을 전달합니다.
  • 색상 변경 처리 (handleColorChange):

    • 사용자가 색상 버튼을 클릭하면 handleColorChange 함수가 호출되어 노트의 배경색을 변경합니다. 변경된 색상은 즉시 상위 컴포넌트에 전달되어 노트의 시각적 구분을 용이하게 합니다.
  • 편집 모드 전환:

    • 편집 시작: 노트를 클릭하면 isEditing 상태가 true로 변경되어 텍스트 영역이 편집 가능 상태로 전환됩니다.
    • 편집 완료: 저장 버튼 (AiOutlineCheck)을 클릭하면 isEditing 상태가 false로 변경되어 편집 모드가 종료됩니다.
    • 편집 취소: 삭제 버튼 (AiOutlineClose)을 클릭하면 e.stopPropagation()을 호출하여 이벤트 전파를 중지시키고, 노트를 삭제합니다.
  • 노트 삭제 버튼 (AiOutlineClose):

    • 사용자가 삭제 버튼을 클릭하면 onRemoveNote 함수가 호출되어 해당 노트가 삭제됩니다. 이때 e.stopPropagation()을 사용하여 노트 클릭 이벤트가 상위 요소로 전파되지 않도록 합니다.
  • 노트 내용 표시 및 편집:

    • 노트가 편집 모드일 때는 텍스트 영역이 편집 가능하게 되며, 색상 선택 버튼이 표시됩니다.
    • 노트가 편집 모드가 아닐 때는 노트의 내용만 표시되고, 삭제 버튼이 보입니다.

추가 설명:

Note 컴포넌트는 사용자가 노트를 직관적으로 수정하고 관리할 수 있도록 다양한 기능을 제공합니다. 노트의 색상 변경 기능을 통해 시각적으로 구분할 수 있으며, 텍스트 영역의 자동 높이 조절 기능은 사용자 경험을 크게 향상시킵니다. 또한, 편집 모드 전환과 이벤트 전파 방지를 통해 사용자가 의도한 동작만을 수행하도록 하여 보다 안정적이고 직관적인 인터페이스를 제공합니다.


📝 한글 입력 이슈 처리

src/components/Note.jsx 한글 입력 문제 해결

import { useEffect, useRef, useState } from 'react';
import { AiOutlineClose, AiOutlineCheck } from 'react-icons/ai';

const Note = ({
  id,
  content,
  color: initialColor,
  onUpdateNote,
  onRemoveNote,
}) => {
  const [localContent, setLocalContent] = useState(content);

  const colorOptions = [
    'bg-yellow-300',
    'bg-pink-300',
    'bg-blue-300',
    'bg-green-300',
  ];

  const [color, setColor] = useState(() => {
    if (initialColor) return initialColor;
    const randomIndex = Math.floor(Math.random() * colorOptions.length);
    return colorOptions[randomIndex];
  });

  const [isEditing, setIsEditing] = useState(false);

  const textareaRef = useRef(null);

  useEffect(() => {
    if (textareaRef.current) {
      textareaRef.current.style.height = 'auto';
      textareaRef.current.style.height =
        textareaRef.current.scrollHeight + 'px';
    }
  }, [content]);

  const handleContentChange = () => {
    onUpdateNote(id, localContent, color);
  };

  const handleColorChange = newColor => {
    setColor(newColor);
    onUpdateNote(id, content, newColor);
  };

  return (
    <div
      className={`p-4 ${color} relative max-h-[32rem] overflow-hidden`}
      onClick={() => setIsEditing(true)}
    >
      <div className="absolute top-2 right-2">
        {isEditing ? (
          <button
            aria-label="Check Note"
            className="text-gray-700"
            onClick={e => {
              e.stopPropagation();
              setIsEditing(false);
            }}
          >
            <AiOutlineCheck size={20} />
          </button>
        ) : (
          <button
            aria-label="Close Note"
            className="text-gray-700"
            onClick={e => {
              e.stopPropagation();
              onRemoveNote(id);
            }}
          >
            <AiOutlineClose size={20} />
          </button>
        )}
      </div>
      <textarea
        ref={textareaRef}
        value={localContent}
        onChange={e => setLocalContent(e.target.value)}
        onBlur={handleContentChange}
        className={`w-full h-full bg-transparent resize-none border-none focus:outline-none text-gray-900 overflow-hidden`}
        aria-label="Edit Note"
        placeholder="메모를 작성하세요."
        style={{ height: 'auto', minHeight: '8rem' }}
        readOnly={!isEditing}
      />
      {isEditing && (
        <div className="flex space-x-2">
          {colorOptions.map((option, index) => (
            <button
              key={index}
              className={`w-6 h-6 rounded-full cursor-pointer outline outline-gray-50 ${option}`}
              onClick={() => handleColorChange(option)}
              aria-label={`Change color to ${option}`}
            />
          ))}
        </div>
      )}
    </div>
  );
};

export default Note;

코드 설명:

  • 로컬 상태 (localContent) 추가:
    • 한글 입력 시 발생하는 이슈를 해결하기 위해 localContent라는 로컬 상태를 도입하였습니다. 이는 노트의 내용을 임시로 저장하여 입력 도중 발생할 수 있는 비동기 문제를 방지합니다.
  • 텍스트 영역의 readOnly 속성:
    • readOnly={!isEditing} 속성을 추가하여 노트가 편집 모드가 아닐 때는 텍스트 영역이 읽기 전용으로 설정됩니다. 이는 사용자가 실수로 내용을 변경하지 않도록 보호합니다.
  • 텍스트 영역의 스타일링:
    • style={{ height: 'auto', minHeight: '8rem' }}를 추가하여 텍스트 영역의 최소 높이를 설정하고, 내용에 따라 자동으로 높이가 조절되도록 했습니다. 이는 한글 입력 시 텍스트 영역의 크기가 적절하게 유지되도록 도와줍니다.
  • 입력 이벤트 핸들링:
    • onBlur={handleContentChange}: 텍스트 영역에서 포커스를 잃을 때(onBlur 이벤트) handleContentChange 함수를 호출하여 변경된 내용을 상위 컴포넌트에 전달합니다. 이는 입력이 완료된 후에만 변경 사항이 반영되도록 합니다.
  • 이벤트 전파 방지:
    • 노트 삭제 버튼과 저장 버튼 클릭 시 e.stopPropagation()을 호출하여 부모 요소로의 이벤트 전파를 방지하였습니다. 이는 노트 내 버튼 클릭 시 노트 전체가 편집 모드로 전환되는 것을 막습니다.

추가 설명:

한글 입력 시 발생할 수 있는 비동기 문제를 해결하기 위해 로컬 상태 localContent를 도입하였습니다. 이는 사용자가 텍스트를 입력하는 동안 실시간으로 노트의 내용을 업데이트하여 입력 도중 발생할 수 있는 데이터 손실을 방지합니다. 또한, readOnly 속성을 통해 노트가 편집 모드가 아닐 때는 내용을 수정할 수 없도록 하여 데이터의 안정성을 확보했습니다.

텍스트 영역의 스타일링을 통해 한글 입력 시 텍스트 영역의 크기가 적절하게 유지되도록 하였으며, onBlur 이벤트를 활용하여 입력이 완료된 후에만 변경 사항을 상위 컴포넌트에 반영하도록 설계하였습니다. 이는 사용자의 의도치 않은 데이터 변경을 방지하고, 입력의 정확성을 높이는 데 기여합니다.


전체 수정 사항 요약 📋

  1. src/components/Note.jsx 수정:

    • 노트 삭제 기능 개선:
      • 삭제 버튼 클릭 시 이벤트 전파를 중지하여 노트 편집 모드 전환 방지.
    • 노트 추가 및 삭제 로직 강화:
      • 로컬 상태 localContent 추가로 한글 입력 이슈 해결.
      • 텍스트 영역의 자동 높이 조절 및 readOnly 속성 도입.
    • 편집 모드 관리:
      • 편집 시작 및 종료 시 이벤트 전파 방지 및 상태 관리 강화.
  2. src/components/LeanCanvas.jsx 수정:

    • 다양한 CanvasCard 컴포넌트 추가:
      • 린캔버스의 모든 섹션을 포괄적으로 관리하기 위해 다양한 섹션별 CanvasCard 추가.
      • 각 섹션의 노트 변경 시 handleNotesChange 함수 호출로 데이터 일관성 유지.
  3. src/components/CanvasCard.jsx 수정:

    • 노트 추가 기능 (handleAddNote):
      • UUID를 사용하여 고유한 id를 가진 새로운 노트 추가.
    • 노트 삭제 기능 (handleRemoveNote):
      • 특정 id를 가진 노트를 필터링하여 삭제.
    • 노트 업데이트 기능 (handleUpdateNote):
      • 특정 노트의 contentcolor를 업데이트하여 전체 노트 배열을 상위 컴포넌트에 전달.
  4. 한글 입력 이슈 처리:

    • src/components/Note.jsx 수정:
      • 로컬 상태 localContent 추가로 한글 입력 시 발생할 수 있는 데이터 손실 방지.
      • 텍스트 영역의 자동 높이 조절 및 readOnly 속성 도입으로 사용자 경험 향상.

배운 내용 요약 📝

이번 린캔버스 수정 작업을 통해 다음과 같은 주요 내용을 학습하고 적용할 수 있었습니다:

  1. 이벤트 전파 관리:

    • e.stopPropagation()을 활용하여 특정 이벤트가 부모 요소로 전파되지 않도록 제어하는 방법을 배웠습니다. 이는 사용자 인터페이스의 예기치 않은 동작을 방지하는 데 유용합니다.
  2. 로컬 상태 관리:

    • 한글 입력 시 발생할 수 있는 비동기 문제를 해결하기 위해 로컬 상태(localContent)를 도입하여 입력 중인 내용을 안정적으로 관리하는 방법을 익혔습니다.
  3. 자동 높이 조절:

    • 텍스트 영역의 높이를 자동으로 조절하여 사용자 입력에 따라 UI가 유동적으로 변화하도록 구현하는 방법을 배웠습니다. 이는 사용자 경험을 크게 향상시키는 중요한 기능입니다.
  4. UUID 활용:

    • uuidv4()를 사용하여 고유한 식별자를 생성함으로써, 동적으로 생성되는 노트의 id를 관리하는 방법을 익혔습니다. 이는 데이터의 신뢰성과 관리의 용이성을 높입니다.
  5. 컴포넌트 분리 및 재사용성:

    • CanvasCardNote 컴포넌트를 통해 린캔버스의 각 섹션과 노트를 독립적으로 관리하고, 재사용 가능한 구조로 설계하는 방법을 배웠습니다. 이는 코드의 유지보수성과 확장성을 크게 향상시킵니다.
  6. 사용자 경험(UX) 향상:

    • 노트의 색상 변경 기능과 자동 높이 조절 기능을 추가하여 사용자 인터페이스를 더욱 직관적이고 편리하게 만들었습니다.
    • 편집 모드 전환 기능을 통해 사용자 참여도를 높이고, 인터랙티브한 UI를 구현하는 방법을 익혔습니다.
  7. 한글 입력 이슈 해결:

    • 로컬 상태와 이벤트 핸들링을 통해 한글 입력 시 발생할 수 있는 문제를 해결하는 방법을 배웠습니다. 이는 다국어 지원 애플리케이션 개발 시 중요한 기술입니다.
  8. 코드 최적화 및 유지보수성 향상:

    • 각 기능을 독립적인 함수로 분리하여 코드의 모듈화를 실현하고, 주석과 문서화를 통해 코드의 이해도를 높였습니다. 이는 향후 유지보수를 용이하게 하고, 팀 내 협업을 원활하게 합니다.

이번 작업을 통해 린캔버스 애플리케이션의 기능을 확장하고, 사용자 경험을 크게 향상시킬 수 있었습니다.

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

0개의 댓글