내가 개발하면서 테스트하는 입장에서도 점을 찍고 거기에 타이틀을 적는게 손이 안간다고해야하나, 자연스럽지 않은 흐름인듯했다.
그래서 간단하게 이모지를 선택할 수 있으면 좋겠다 싶어서 emoji-picker-react 라이브러리를 이용했다.
https://www.npmjs.com/package/emoji-picker-react#hiddenemojis---excluding-certain-emojis
emoji-picker-react
Emoji Picker component for React Applications on the web. Latest version: 4.12.0, last published: 5 months ago. Start using emoji-picker-react in your project by running `npm i emoji-picker-react`. There are 284 other projects in the npm registry using emo
www.npmjs.com
설명이 나름 잘 되어있는거같은데, onEmojiClick 함수 타입 정의하는데서 좀 애먹었다.
문제점
1. 페이지 로드 시 이모지 피커가 열려있음
showPicker 값은 false임
2. 이모지를 선택해도 setTitle이 되지않음
전체 코드
import { ChangeEvent, MouseEvent as ReactMouseEvent, useEffect, useRef, useState } from "react";
import Point from "../Point/Point";
import { useGraphStore } from "../../../../store/useGraphStore";
import GraphContainer from "./GraphContainer";
import EmojiPicker, { EmojiClickData } from "emoji-picker-react";
import { MouseDownEvent } from "emoji-picker-react/dist/config/config";
const Graph = () => {
const { points, addPoint, setTitle } = useGraphStore();
const inputRef = useRef<HTMLInputElement>(null);
const [showPicker, setShowPicker] = useState(false);
const handleClick = (e: ReactMouseEvent<HTMLDivElement>) => {
const rect = e.currentTarget.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
addPoint({ id: Date.now(), x, y, title: "" }); // 클릭한 좌표 추가
};
const handleChange = (e: ChangeEvent<HTMLInputElement>, id: number) => {
setTitle(id, e.target.value);
setShowPicker(false);
};
useEffect(() => {
inputRef?.current?.focus();
setShowPicker(true);
}, [points]);
const handleClickEmoji: MouseDownEvent = (emoji: EmojiClickData, e: MouseEvent) => {
setTitle(Number(inputRef.current?.id), emoji.emoji);
};
return (
<GraphContainer onClick={handleClick}>
{points.map((point) => (
<Point
key={point.id}
x={point.x}
y={point.y}
title={point.title} // input.value로 전달하는 값
onChange={(e) => handleChange(e, point.id)}
ref={inputRef}
/>
))}
<EmojiPicker
open={showPicker}
onEmojiClick={handleClickEmoji}
style={{
position: "absolute",
top: `${points.at(-1)?.y}px`,
left: `${points.at(-1)?.x}px`,
}}
/>
</GraphContainer>
);
};
export default Graph;
고민하다가 결국 지피티로 해결했다.
우선, 위 코드의 잘못된 점
useEffect(() => {
inputRef?.current?.focus();
setShowPicker(true);
}, [points]);
const handleClickEmoji: MouseDownEvent = (emoji: EmojiClickData, e: MouseEvent) => {
setTitle(Number(inputRef.current?.id), emoji.emoji);
};
1. 잘못된 inputRef 사용
이전에 구현한 코드에서 points 배열에 새로운 point가 추가될때마다 마지막 point에 focus 를 주도록 함
즉 inputRef 는 항상 마지막에 렌더링된 input을 가리키고 있다.
따라서 inputRef.current.id 로 접근해서 emoji를 추가하는건 유저가 수정하려는 input이 아닐 수 있다.
<EmojiPicker
open={showPicker}
onEmojiClick={handleClickEmoji}
style={{
position: "absolute",
top: `${points.at(-1)?.y}px`,
left: `${points.at(-1)?.x}px`,
}}
/>
2. open = {true} 로 하되, Picker 컴포넌트를 조건부 렌더링을 하자
변경한 내용
1. 선택한 input의 id 를 로컬 상태로 관리하자
-> 선택된 값이 있을때 Picker 열도록 한다.
-> setTitle에 선택된 id를 넘겨줄수 있다.
// 화면을 클릭해서 Point 컴포넌트를 생성하는 핸들러
const handleClick = (e: ReactMouseEvent<HTMLDivElement>) => {
const rect = e.currentTarget.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const newPoint = { id: Date.now(), x, y, title: "" };
addPoint(newPoint);
setActivePoint(newPoint.id); // 새로 추가한 포인트를 활성화
};
// Point 내부의 input value를 관리하는 핸들러
const handleChange = (e: ChangeEvent<HTMLInputElement>, id: number) => {
setTitle(id, e.target.value);
setActivePoint(null); // 입력이 끝나면 이모지 피커 닫기
};
그래프를 클릭해서 Point 컴포넌트를 추가하는 handleClick 핸들러에서
새롭게 추가하는 id 값을 activePoint 로 저장한다.
input change핸들러에서 setTitle은 그대로 유지하고, activePoint = null 로 할당해서 Picker 닫기
{activePoint && (
<EmojiPicker
open={true}
onEmojiClick={handleClickEmoji}
style={{
position: "absolute",
top: `${points.find((p) => p.id === activePointId)?.y}px`,
left: `${points.find((p) => p.id === activePointId)?.x}px`,
}}
/>
)}
setShowPicker, ref 로 구현하려고 했던 두 가지 역할을 activePoint라는 활성화된 특정 id값으로 구현하게 되었다.
++ 이모지를 선택하지 않고 다음 점을 찍고, 이모지 선택하면 자꾸만 새로 생긴 점이 아닌 이전 점에 이모지가 title로 들어가는 문제가 생겼는데 해결하지 못해 이모지 피커를 빼버렸다 ㅠ 그리고 기본 값으로 📍핀 이모지를 넣어주는 것으로 마무리했다..
'개발개발 > LifeGraph_인생그래프' 카테고리의 다른 글
[인생 그래프] 카카오톡 인앱 브라우저 탈출하기 (0) | 2025.02.13 |
---|---|
[인생 그래프] SCSS 반응형 디자인 구현하기 (0) | 2025.02.12 |
[인생 그래프] 이미지 저장하기 (html2canvas + file-saver) (0) | 2025.02.11 |
[인생 그래프] 클릭 이벤트 핸들러 뜯어보기 (0) | 2025.02.11 |
[인생 그래프] 그래프가 이상하다 (0) | 2025.02.10 |