CardFront 컴포넌트를 클릭 시 뒷면 Modal이 호출 되도록 코드를 작성 했었는데, 도중에 다른 형태의 Modal을 불러올 경우가 생기게 되었다.
컴포넌트를 하나 더 만들려고 했다가 더 효율적인 방법이 없을까 찾아보던 중 children을 사용하여 할 수 있을 것 같아 컴포넌트의 구조를 바꾸어 보았다.
Modal은 정상적으로 동작했지만 문제가 있었다.
CardFront 컴포넌트에서 children으로 CardModal을 불러와야 한다.
CardModal컴포넌트 on, off를 CardFront컴포넌트의 state로 관리 했었는데 CardList의 state로 관리하면 모든 Modal이 열려 버린다.
결국 CardFront의 state로 관리해야 할 것 같은데 어떤 식으로 관리 해야 할 지 생각이 안난다.
// CardList.js
const [showModal, setShowMadal] = React.useState(false);
return (
<Grid>
<Div>
{cardList.allIds.map((userId) => {
return (
<CardFront key={userId} userId={userId}>
<CardModal show={showModal} onHide={closeModal} userId={userId} />
</CardFront>
);
})}
</Div>
</Grid>
);
};
// CardFront.js
return (
<Grid
width="350px"
height="200px"
borderRadius="16px"
border="1px solid black"
margin="16px"
_onClick={behind}
>
<Grid _onClick={stopPropagation}>
{children}
</Grid>
<Div is_flex>
<Image shape="circle" src={front[userId]?.profile} />
<Grid width="30%" margin="0px 20px">
<Text>{front[userId]?.userName}</Text>
<Text color="#7F7C82" bold>
# {stackHashTags}
</Text>
</Grid>
</Div>
<Hash>
{interestHashTags?.map((stack, idx) => {
return stack && <HashTag key={idx} tag={stack} />;
})}
</Hash>
<Grid _onClick={stopPropagation}>
{contap && select === 'ReceiveTap' && (
<button type="button" onClick={acceptTap}>
수락
</button>
)}
{contap && select === 'ReceiveTap' && (
<button type="button" onClick={rejectTap}>
거절
</button>
)}
</Grid>
</Grid>
);
};
계속 생각을 해보니까 두가지 정도의 방법이 생각 났는데 CardFront를 부르기 전에 CardBundle 컴포넌트를 먼저 호출해서 그 안에서 state로 관리하면 될 것 같았다.
// CardList.js
return (
<Grid>
<Div>
{cardList.allIds.map((userId) => {
return (
<CardBundle key={userId} userId={userId} />
);
})}
</Div>
</Grid>
);
};
// CardBundle.js
const [showModal, setShowMadal] = React.useState(false);
return (
<Grid>
<CardFront key={userId} userId={userId}>
<CardModal show={showModal} onHide={closeModal} userId={userId} />
</CardFront>
</Grid>
);
};
근데 굳이 이렇게 할거면 그냥 다른 Modal 컴포넌트를 만들어서 하는게 나을 것 같다는 생각에 children으로 관리하는건 잠시 미뤄두었다.
그 다음으로 넘어갔더니 다시 더 큰 고민이 생겼다.
CardFront 컴포넌트를 클릭 시 ContapModal을 불러온다.
// CardFront.js
const [showModal, setShowMadal] = React.useState(false);
return (
<Grid
width="350px"
height="200px"
borderRadius="16px"
border="1px solid black"
margin="16px"
_onClick={behind}
>
<Grid _onClick={stopPropagation}>
{!contap && <CardModal show={showModal} onHide={closeModal} userId={userId} />}
{contap && <ContapModal show={showModal} onHide={closeModal} userId={userId} />}
</Grid>
<Div is_flex>
<Image shape="circle" src={front[userId]? front[userId].profile : null} />
<Grid width="30%" margin="0px 20px">
<Text>{front[userId]? front[userId].userName : null}</Text>
<Text color="#7F7C82" bold>
</Text>
</Grid>
</Div>
<Grid _onClick={stopPropagation}>
{contap && select === 'ReceiveTap' && (
<button type="button" onClick={acceptTap}>
수락
</button>
)}
{contap && select === 'ReceiveTap' && (
<button type="button" onClick={rejectTap}>
거절
</button>
)}
</Grid>
</Grid>
);
};
그 ContapModal은 CardFront 컴포넌트를 사용할 수 있는가?
없다면 새로운 컴포넌트를 만들어서 다시 사용해야 하나?
컴포넌트의 재 사용성을 고려해서 만들었다면 당연히 사용 할 수 있는 것 아닌가?
사용이 안된다면 나는 그 컴포넌트를 재사용성을 고려해서 만들지 못한건가?
당연히 사용할 수 있을거라는 생각은 있었는데 일단 ESLint에서 계속 걸려서 뭔가 잘못된 것 같아 리팩토링할때 신경쓰기로 하고 컴포넌트를 하나 더 만들었다.
// CardFrontContap.js
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import { useSelector } from 'react-redux';
import { Grid, Image, Text } from '../elements';
import HashTag from './HashTag';
const CardFrontContap = ({ userId, onModal }) => {
const front = useSelector((state) => state.taps.byId);
const stackHashTags = front[userId].hashTags
?.split('_')[0]
.split('@')
.slice(1, 2);
const interestHashTags = front[userId].hashTags
?.split('_')[1]
.split('@')
.slice(1, 4);
console.log(stackHashTags, interestHashTags);
const stopPropagation = (e) => {
e.stopPropagation();
};
return (
<Grid
width="350px"
height="200px"
borderRadius="16px"
border="1px solid black"
margin="16px"
_onClick={onModal}
>
<Div is_flex>
<Image
shape="circle"
src={front[userId] ? front[userId].profile : null}
/>
<Grid width="30%" margin="0px 20px">
<Text>{front[userId] ? front[userId].userName : null}</Text>#{' '}
{stackHashTags}
<Text color="#7F7C82" bold />
</Grid>
</Div>
<Hash>
{interestHashTags?.map((stack, idx) => {
return stack && <HashTag key={idx} tag={stack} />;
})}
</Hash>
<Grid _onClick={stopPropagation} />
</Grid>
);
};
CardFrontContap.propTypes = {
userId: PropTypes.number.isRequired,
onModal: PropTypes.func.isRequired,
};
export default CardFrontContap;
const Div = styled.div`
display: flex;
justify-content: center;
align-items: center;
margin: 10% 0px;
`;
const Hash = styled.div`
display: flex;
margin: -10px 10px;
`;
CardFront 컴포넌트를 클릭 하면 ContapModal이 열린다. o
ContapModal 컴포넌트에는 CardFrontContap 컴포넌트가 있다. o
CardFrontContap 컴포넌트를 클릭 하면 CardModal이 열린다. o
CardModal이 열리면 ContapModal이 닫힌다. x (둘다 열리거나 닫힌다.)
두가지의 Modal을 핸들링하는게 계속 안되서 결국 자려고 누웠는데 문득 children으로 하면 될 것 같다는 생각이 나서 다시 컴퓨터를 켜고 생각나는 대로 작성 했더니 어찌저찌 성공했다.
핵심은 children props를 사용해서 컴포넌트 깊숙히 있던 Modal을 밖으로 최대한 꺼내와서 state로 관리했는데 이 방법이 옳은 방법인지는 나중에 더 찾아봐야 알 수 있을 것 같다.
// CardFront.js
// 메인페이지 : 카드 뒷면 모달, 컨탭페이지 : 사이드 모달
const [showModal, setShowMadal] = React.useState(false);
// 사이드 모달 안에있는 카드 뒷면 모달
const [showModalInSideModal, setShowModaInSideModal] = React.useState(false);
const showCardBackModal = () => {
if (!showModal) {
dispatch(loadCurrentCardDB(userId));
}
setShowMadal(true);
};
const closeModal = () => {
setShowMadal(false);
};
const handleSideModal = () => {
setShowMadal(false);
setShowModaInSideModal(true);
};
const closeSideModal = () => {
setShowModaInSideModal(false);
setShowMadal(true);
};
return (
<Grid
width="350px"
height="200px"
borderRadius="16px"
border="1px solid black"
margin="16px"
_onClick={behind}
>
<Grid _onClick={stopPropagation}>
{!contap && (
<CardModal show={showModal} onHide={closeModal} userId={userId} />
)}
{contap && (
<ContapModal
className="contapModal"
show={showModal}
onHide={closeModal}
userId={userId}
>
<CardFrontContap onModal={handleSideModal} userId={userId} />
</ContapModal>
)}
{showModalInSideModal && (
<CardModal show={showModalInSideModal} onHide={closeSideModal} userId={userId} />
)}
</Grid>
<Div is_flex>
<Image
shape="circle"
src={front[userId] ? front[userId].profile : null}
/>
<Grid width="30%" margin="0px 20px">
<Text>{front[userId] ? front[userId].userName : null}</Text>#{' '}
# {stackHashTags}
<Text color="#7F7C82" bold />
</Grid>
</Div>
<Hash>
{interestHashTags?.map((stack, idx) => {
return stack && <HashTag key={idx} tag={stack} />;
})}
</Hash>
<Grid _onClick={stopPropagation}>
{contap && select === 'ReceiveTap' && (
<button type="button" onClick={acceptTap}>
수락
</button>
)}
{contap && select === 'ReceiveTap' && (
<button type="button" onClick={rejectTap}>
거절
</button>
)}
</Grid>
</Grid>
);
};