Damage Relations 컴포넌트 생성하기
import React, {useEffect, useState} from 'react'
const DamageRelations = ({damages}) => {
const [damagePokemonForm, setDamagePokemonForm] = useState()
useEffect(() => {
const arrayDamage = damages.map((damage) => separateObjectBetweenToAndFrom(damage))
// type이 2개인지 1개인지 구분해서 데이터 가공
if(arrayDamage.length === 2) {
const obj = joinDamageRelations(arrayDamage)
setDamagePokemonForm(reduceDuplicateValues(postDamageValue(obj.from)))
} else{
setDamagePokemonForm(postDamageValue(arrayDamage[0].from))
}
}, [damages])
const joinDamageRelations = (props) => {
return {
to: joinObjects(props, 'to'),
from: joinObjects(props, 'from'),
}
}
const reduceDuplicateValues = (props) => {
const duplicateValues = {
double_damage: '4x',
half_damage: '1/4x',
no_damage: '0x'
}
return Object.entries(props)
.reduce((acc, [keyName, value]) => {
const key = keyName
const verifiedValue = filterForUniqueValues(
value,
duplicateValues[key]
)
return (acc = { [keyName]: verifiedValue, ...acc})
}, {})
}
const filterForUniqueValues = (valueForFiltering, damageValue) => {
return valueForFiltering.reduce((acc, currentValue) => {
const {url, name} = currentValue
const filterACC = acc.filter((a) => a.name !== name)
return filterACC.length === acc.length
? (acc = [currentValue, ...acc])
: (acc = [{damageValue: damageValue, name, url}, ...filterACC])
}, [])
}
const joinObjects = (props, string) => {
const key = string
const firstArrayValue = props[0][key]
const secondArrayValue = props[1][key]
const result = Object.entries(secondArrayValue)
.reduce((acc, [keyName, value]) => {
const result = firstArrayValue[keyName]?.concat(value)
return (acc = {[keyName]: result, ...acc})
}, {})
return result
}
const postDamageValue = (props) => {
const result = Object.entries(props)
.reduce((acc, [keyName, value]) => {
const valuesOfKeyName = {
double_damage: '2x',
half_damage: '1/2x',
no_damange: '0x'
}
return (acc = {
[keyName]: value.map(i => ({
damageValue: valuesOfKeyName[keyName],
...i
})),
...acc
})
}, {})
return result
}
// 데미지 from과 to 분리
const separateObjectBetweenToAndFrom = (damage) => {
const from = filterDamageRelations('_from', damage)
const to = filterDamageRelations('_to', damage)
return {from, to}
}
const filterDamageRelations = (valueFilter, damage) => {
const result = Object.entries(damage)
.filter(([keyName, value]) => {
return keyName.includes(valueFilter)
})
.reduce((acc, [keyName, value]) => {
const keyWithValueFilterRemove = keyName.replace(valueFilter, '')
return (acc = {[keyWithValueFilterRemove]: value, ...acc})
}, {})
return result
}
return (
<div>DamageRelations</div>
)
}
export default DamageRelations
src폴더 안에 components폴더 안에 DamageRelations.jsx파일입니다.
Damage Relations UI 생성하기
return (
<div className='flex gap-2 flex-col'>
{damagePokemonForm ? (
<>
{Object.entries(damagePokemonForm)
.map(([keyName, value]) => {
const key = keyName
const valuesOfKeyName = {
double_damage: 'Weak',
half_damage: 'Resistant',
no_damage: 'Immune'
}
return (
<div key={key}>
<h3 className='capitalize font-medium text-sm md:text-base text-slate-500 text-center'>
{valuesOfKeyName[key]}
</h3>
<div className="flex flex-wrap gap-1 justify-center">
{value.length > 0 ? (
value.map(({name, url, damageValue}) => {
return (
<Type type={name} key={url} damageValue={damageValue} />
)
})
) : (
<Type type={'none'} key={'none'} />
)
}
</div>
</div>
)
})}
</>
) : <div></div>
}
</div>
)
src폴더 안에 components폴더 안에 DamageRelations.jsx파일입니다.
Damage Relations 모달 생성하기
import React from 'react'
import DamageRelations from './DamageRelations'
const DamageModal = ({setIsModalOpen, damages}) => {
return (
<div className='flex items-center justify-center z-40 fixed left-0 bottom-0 w-full h-full bg-gray-800'>
<div className="modal bg-white rounded-lg w-1/2">
<div className="flex flex-col items-start p-4">
<div className="flex items-center w-full justify-between">
<div className="text-gray-900 font-medium text-lg">
데미지 관계
</div>
<span
onClick={() => setIsModalOpen(false)}
className="text-gray-900 font-medium text-lg cursor-pointer">
X
</span>
</div>
<DamageRelations damages={damages} />
</div>
</div>
</div>
)
}
export default DamageModal
src폴더 안에 components폴더 안에 DamageModal.jsx파일입니다.
const [isModalOpen, setIsModalOpen] = useState(false)
src폴더 안에 pages폴더 안에 DetailPage폴더 안에 index.jsx파일에 모달창에 관한 useState를 만듭니다.
onClick={() => setIsModalOpen(true)}
이미지에 클릭할 시 modal이 true로 되며 오픈할 수 있겠끔 작업합니다.
{isModalOpen && <DamageModal setIsModalOpen={setIsModalOpen} damages={pokemon.DamageRelations} />}
index.jsx UI부분에 모달창을 띄울 수 있게 작업합니다.
모달창 외부 클릭시 모달창 닫게 만드는 Custom Hooks생성하기
import { useEffect } from "react";
export default function useOnClickOutside(ref, handler) {
useEffect(() => {
const listener = (event) => {
// 모달 안에 클릭 시 닫지 않고 유지
if(!ref.current || ref.current.contains(event.target)){
return
}
// 모달 밖을 클릭 시 닫게 해줌
handler()
}
document.addEventListener('mousedown', listener)
return () => {
document.removeEventListener('mousedown', listener)
}
}, [])
}
src폴더 안에 hooks폴더 안에 useOnClickOutside.js파일의 내용입니다.
src폴더 안에 components폴더 안에 DamageModal.jsx파일 추가 내용입니다.
'배워서 따라하는 포플 > 포켓몬 도감 앱' 카테고리의 다른 글
타입스크립트로 변경하기(1) (0) | 2023.09.18 |
---|---|
로그인 페이지 생성하기 (0) | 2023.09.17 |
상세 페이지 생성하기(3) (0) | 2023.09.17 |
상세 페이지 생성하기(1) (0) | 2023.09.14 |
메인 페이지 생성하기 (0) | 2023.09.09 |