React Query를 이용한 에러핸들링을 하던 중 에러가 React Query에서 에러가 포착되지 않고 connectGPT 로직 내부에서 에러가 포착되어서 확인해본 결과 아래처럼 error promise를 반환해 주거나 에러 핸들링을 react query의 onError 콜백을 사용했어야 했다
// ../api/connectGPT
try{
// ...gpt post
} catch (error) {
console.error(error);
throw error; // error 반환 추가
}
import { ChangeEvent, FormEvent, useState } from 'react';
import { connectGPT } from '../api/connectGPT';
import { useMutation } from '@tanstack/react-query';
import { PacmanLoader } from 'react-spinners';
export default function Container() {
const [inputValue, setInputValue] = useState<string>('');
const [result, setResult] = useState<string>('');
const { mutate, isLoading, isError } = useMutation(
['gpt', inputValue],
() => connectGPT(inputValue),
{
onSuccess: (data) => {
setResult(data);
},
onError: (error) => {
console.error(error);
},
}
);
const colorCodeRegex = /#[A-Fa-f0-9]{6}\b/g;
const colorCodes = result && result.match(colorCodeRegex);
const splitResult = result && result.split('.');
const onSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
mutate();
};
const onChange = (e: ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value);
};
return (
<div className='flex justify-center items-center h-screen '>
<section className=' bg-primary dark:bg-primary-dark text-secondary dark:text-secondary-dark p-12 shadow-xl flex flex-col items-center rounded-lg overflow-hidden transition'>
<h1 className=' text-4xl font-bold mb-8'>색조합 3가지 추천</h1>
<form onSubmit={onSubmit}>
<input
type='text'
placeholder='색깔을 입력하세요'
value={inputValue}
onChange={onChange}
required
className='border border-primary dark:border-primary-dark bg-secondary dark:bg-secondary-dark text-secondary dark:text-secondary-dark rounded-md p-2 text-center mb-6'
/>
</form>
{isLoading && (
<PacmanLoader className=' mb-6' color='#ffee00' size={25} />
)}
{isError && (
<div className=' text-red-500 font-semibold mb-6'>
에러가 발생했습니다.
</div>
)}
{splitResult && <GptResponse splitResult={splitResult} />}
{colorCodes && <RecommendColor colorCodes={colorCodes} />}
<DarkModeBtn />
</section>
</div>
);
}
전에 사용해본 Context API 를 이용해 다크모드 상태관리를 하였고
velog처럼 버튼 클릭 시 애니메이션을 구현해보고 싶어서 진행해 보았다.
// /components/DarkModeBtn
import { useDarkMode } from '../context/DarkModeContext';
import { useTransition, animated } from '@react-spring/web';
import { HiMoon, HiSun } from 'react-icons/hi';
export default function DarkModeBtn() {
const { darkMode, toggleDarkMode } = useDarkMode();
const transitions = useTransition(darkMode, {
initial: {
transform: 'scale(1) rotate(0deg)',
opacity: 1,
},
from: {
transform: 'scale(0) rotate(-180deg)',
opacity: 0,
},
enter: {
transform: 'scale(1) rotate(0deg)',
opacity: 1,
},
leave: {
transform: 'scale(0) rotate(180deg)',
opacity: 0,
},
reverse: true,
});
return (
<>
<button
onClick={toggleDarkMode}
className=' relative cursor-pointer text-3xl mt-4'
>
{transitions((style, item) => {
return item ? (
<div className='absolute top-1/2 -translate-x-1/2 -translate-y-1/2'>
<animated.div style={style}>
<HiSun />
</animated.div>
</div>
) : (
<div className='absolute top-1/2 -translate-x-1/2 -translate-y-1/2'>
<animated.div style={style}>
<HiMoon />
</animated.div>
</div>
);
})}
</button>
</>
);
}
그리고 유지보수가 편하게끔 다크모드에 따른 색상을 tailwind.config.js에 정의해두었다.
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./src/**/*.{js,jsx,ts,tsx}'],
theme: {
extend: {
backgroundColor: {
primary: '#f8f9fa',
'primary-dark': '#121212',
secondary: '#ffffff',
'secondary-dark': '#1E1E1E',
},
textColor: {
primary: '#212529',
'primary-dark': '#ececec',
secondary: '#495057',
'secondary-dark': '#D9D9D9',
},
borderColor: {
primary: '#343A40',
'primary-dark': '#E0E0E0',
},
},
},
darkMode: 'class',
plugins: [],
};
처음에는 아래 방식대로 작성을 했는데 클립보드 저장이 되기전에 alert가 실행되어서 확인해봤더니 성공할 경우 Promise를 반환하기 때문에 then 체이닝을 통해 alert를 실행 시켜줘야했다
// /utils/copyText.ts
// 정상 작동 X
export const copyText = (text: string) => {
navigator.clipboard.writeText(text)
alert('클립보드에 복사되었습니다.');
};
// /utils/copyText.ts
// 정상 작동 O
export const copyText = (text: string) => {
navigator.clipboard
.writeText(text)
.then(() => alert('클립보드에 복사되었습니다.'));
};
https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText
Github - https://github.com/Taeyooooon/openai_toypj
https://tanstack.com/query/v4/docs/react/overview
https://velog.io/@velopert/velog-dark-mode