diff --git a/src/components/create-character/hooks/useCreateCharacter.tsx b/src/components/create-character/hooks/useCreateCharacter.tsx index 1d02d84..65f056b 100644 --- a/src/components/create-character/hooks/useCreateCharacter.tsx +++ b/src/components/create-character/hooks/useCreateCharacter.tsx @@ -1,10 +1,10 @@ 'use client'; import { useContext } from 'react'; -import { CreateCharacterDispatchContext } from '@/context/create-character-provider'; +import { CreateCharacterContext } from '@/context/create-character-provider'; export default function useCreateCharacter() { - const createCharacterDispatch = useContext(CreateCharacterDispatchContext); + const createCharacterDispatch = useContext(CreateCharacterContext); if (createCharacterDispatch === null) throw new Error('CreateCharacter Provider를 감싸서 사용하세요'); diff --git a/src/components/create-character/steps/select-color.tsx b/src/components/create-character/steps/select-color.tsx index e6c7c32..c4728d9 100644 --- a/src/components/create-character/steps/select-color.tsx +++ b/src/components/create-character/steps/select-color.tsx @@ -1,8 +1,7 @@ import React, { useContext, useState } from 'react'; import { CarouselDispatchContext } from '..'; -import Header from '../header'; import Intro from '../intro'; -import { CreateCharacterDispatchContext } from '@/context/create-character-provider'; +import { useCreateCharacterContext } from '@/context/create-character-provider'; import CtaButton from '@/components/ui/cta-button'; import CheckCircle from '@/assets/icons/check-circle.svg'; import FixedBottomArea from '../fixed-bottom-area'; @@ -12,13 +11,13 @@ type ColorId = (typeof Colors)[number]['id']; export default React.memo(function SelectColor() { const [selected, setSelected] = useState(null); - const createCharacterDispatch = useContext(CreateCharacterDispatchContext); + const { setValue } = useCreateCharacterContext(); const carouselDispatch = useContext(CarouselDispatchContext); const handleClick = () => { if (selected === null) return; - createCharacterDispatch?.setValue('colorIdx', selected); + setValue('colorIdx', selected); carouselDispatch?.handleNextClick(); }; diff --git a/src/components/create-character/steps/select-item.tsx b/src/components/create-character/steps/select-item.tsx index a9207ed..199aec7 100644 --- a/src/components/create-character/steps/select-item.tsx +++ b/src/components/create-character/steps/select-item.tsx @@ -2,16 +2,16 @@ import Header from '../header'; import Intro from '../intro'; import React, { useState } from 'react'; import useCarousel from '../hooks/useCarousel'; -import useCreateCharacter from '../hooks/useCreateCharacter'; import FixedBottomArea from '../fixed-bottom-area'; import { Items, NO_ITEM_IDX } from '@/constants/character-info'; import CtaButton from '@/components/ui/cta-button'; +import { useCreateCharacterContext } from '@/context/create-character-provider'; type ItemId = (typeof Items)[number]['id']; export default React.memo(function SelectItem() { const [selected, setSelected] = useState(null); - const { setValue } = useCreateCharacter(); + const { setValue } = useCreateCharacterContext(); const { handleNextClick } = useCarousel(); const handleClick = () => { diff --git a/src/components/create-character/steps/select-keywords.tsx b/src/components/create-character/steps/select-keywords.tsx index f5bf910..3f732a8 100644 --- a/src/components/create-character/steps/select-keywords.tsx +++ b/src/components/create-character/steps/select-keywords.tsx @@ -4,15 +4,15 @@ import React, { useState } from 'react'; import CtaButton from '@/components/ui/cta-button'; import useCarousel from '../hooks/useCarousel'; import FixedBottomArea from '../fixed-bottom-area'; -import useCreateCharacter from '../hooks/useCreateCharacter'; import { Keywords } from '@/constants/character-info'; +import { useCreateCharacterContext } from '@/context/create-character-provider'; type KeywordId = (typeof Keywords)[number]['id']; export default React.memo(function SelectKeywords() { const { handleNextClick } = useCarousel(); - const { setValue } = useCreateCharacter(); + const { setValue } = useCreateCharacterContext(); const [selected, setSelected] = useState>([]); @@ -28,7 +28,6 @@ export default React.memo(function SelectKeywords() { const handleNextButtonClick = () => { if (selected.length === 0) { - // TODO: 나중에 toast로 바꾸기 alert('키워드를 한 개 이상 선택해 주세요.'); return; } diff --git a/src/components/create-character/steps/select-shape.tsx b/src/components/create-character/steps/select-shape.tsx index a5c68bc..2c0d76f 100644 --- a/src/components/create-character/steps/select-shape.tsx +++ b/src/components/create-character/steps/select-shape.tsx @@ -6,15 +6,15 @@ import React, { useState } from 'react'; import FixedBottomArea from '../fixed-bottom-area'; import Header from '../header'; import useCarousel from '../hooks/useCarousel'; -import useCreateCharacter from '../hooks/useCreateCharacter'; import Intro from '../intro'; +import { useCreateCharacterContext } from '@/context/create-character-provider'; type ShapeId = (typeof Shapes)[number]['id']; export default React.memo(function SelectShape() { const [selected, setSelected] = useState(null); - const { setValue } = useCreateCharacter(); + const { setValue } = useCreateCharacterContext(); const { handleNextClick } = useCarousel(); const handleSelect = (id: ShapeId) => { diff --git a/src/components/create-character/steps/set-name.tsx b/src/components/create-character/steps/set-name.tsx index 15085b3..ef6d89c 100644 --- a/src/components/create-character/steps/set-name.tsx +++ b/src/components/create-character/steps/set-name.tsx @@ -4,11 +4,13 @@ import Intro from '../intro'; import useCarousel from '../hooks/useCarousel'; import useCreateCharacter from '../hooks/useCreateCharacter'; import FixedBottomArea from '../fixed-bottom-area'; +import { useCreateCharacterContext } from '@/context/create-character-provider'; const NAME_REGEX = /^[ㄱ-ㅎ|ㅏ-ㅣ|가-힣a-zA-Z\s]{1,8}$/; export default React.memo(function SetName() { - const { setValue } = useCreateCharacter(); + console.log('name rerender'); + const { setValue } = useCreateCharacterContext(); const { handleNextClick } = useCarousel(); const nameRef = useRef(null); diff --git a/src/components/create-character/steps/show-result.tsx b/src/components/create-character/steps/show-result.tsx index c99f594..8533535 100644 --- a/src/components/create-character/steps/show-result.tsx +++ b/src/components/create-character/steps/show-result.tsx @@ -3,7 +3,11 @@ import HomeBg from '@/assets/images/homeBg.jpg'; import CtaButton from '@/components/ui/cta-button'; import { Keywords, NO_ITEM_IDX } from '@/constants/character-info'; -import { CreateCharacterValues, CreateCharacterValuesContext } from '@/context/create-character-provider'; +import { + CreateCharacterContext, + CreateCharacterValues, + useCreateCharacterContext, +} from '@/context/create-character-provider'; import { sendGTMEvent } from '@next/third-parties/google'; import { getCookie, setCookie } from 'cookies-next'; import Image from 'next/image'; @@ -35,15 +39,10 @@ export default function ShowResult() { const searchParams = useSearchParams(); const step = searchParams.get('step'); - const createCharacterValues = useContext(CreateCharacterValuesContext); + const { getValues } = useCreateCharacterContext(); + const values = getValues(); - if (createCharacterValues === null) { - alert('처음부터 하세요.'); - router.push('/'); - throw new Error(''); - } - - const { colorIdx, shapeIdx, name, keywords, itemIdx } = createCharacterValues; + const { colorIdx, shapeIdx, name, keywords, itemIdx } = values; const characterImg = `https://kr.object.ncloudstorage.com/kekeche-character/character/${shapeIdx}/0/${colorIdx}.webp`; const itemImg = itemIdx !== NO_ITEM_IDX ? `https://kr.object.ncloudstorage.com/kekeche-character/item/${itemIdx}.webp` : null; @@ -54,14 +53,14 @@ export default function ShowResult() { const handleNextBtnClick = async () => { try { // 캐릭터 생성 api... - const { id } = await createCharacter(createCharacterValues, `${getCookie('accessToken')}`); + const { id } = await createCharacter(values, `${getCookie('accessToken')}`); router.push(`/character/${id}`); router.refresh(); sendGTMEvent({ event: 'createCharacter' }); } catch (err) { // 로그인 안 한 사람->'앗' 페이지 console.log(err); - setCookie('create-character', JSON.stringify(createCharacterValues)); + setCookie('create-character', JSON.stringify(values)); handleNextClick(); } }; diff --git a/src/context/create-character-provider.tsx b/src/context/create-character-provider.tsx index 8494fb0..d3f2343 100644 --- a/src/context/create-character-provider.tsx +++ b/src/context/create-character-provider.tsx @@ -1,6 +1,6 @@ 'use client'; -import { createContext, useCallback, useMemo, useRef, useState } from 'react'; +import { createContext, useCallback, useContext, useMemo, useRef } from 'react'; type Props = { children: React.ReactNode; @@ -15,12 +15,13 @@ export interface CreateCharacterValues { itemIdx?: number | null; } -interface CreateCharacterDispatch { +interface CreateCharacterContext { setValue(target: T, value: CreateCharacterValues[T]): void; + getValue(target: T): CreateCharacterValues[T]; + getValues(): CreateCharacterValues; } -export const CreateCharacterValuesContext = createContext(null); -export const CreateCharacterDispatchContext = createContext(null); +export const CreateCharacterContext = createContext(null); export default function CreateCharacterProvider({ children }: Props) { const createCharacterValues = useRef({}); @@ -35,13 +36,25 @@ export default function CreateCharacterProvider({ children }: Props) { [], ); - const memoizedSetValue = useMemo(() => ({ setValue }), [setValue]); + const getValue = useCallback((target: T) => { + return createCharacterValues.current[target]; + }, []); - return ( - - - {children} - - - ); + const getValues = useCallback(() => { + return createCharacterValues.current; + }, []); + + const memoizedValue = useMemo(() => ({ setValue, getValue, getValues }), [getValue, getValues, setValue]); + + return {children}; +} + +export function useCreateCharacterContext() { + const createCharacterContext = useContext(CreateCharacterContext); + + if (createCharacterContext === null) { + throw new Error('CreateCharacterContext를 감싸서 사용하세요.'); + } + + return createCharacterContext; }