
하단에 간단한 모달을 만드는 기본 예시를 확인해 보자!
import React, { useState } from 'react';
import Modal from './components/Modal2';
import styled from 'styled-components';
const App = () => {
const [isModalOpen, setIsModalOpen] = useState(false);
const handleOpenModal = () => {
setIsModalOpen(true);
};
const handleCloseModal = () => {
setIsModalOpen(false);
};
return (
<Container>
<h1>Welcome to my app!</h1>
<button onClick={handleOpenModal}>Open Modal</button>
{isModalOpen && (
<Modal title="Hello 😉" content="Welcome Modal World" onClose={handleCloseModal} />
)}
</Container>
);
};
export default App;
const Container = styled.div`
width: 500px;
margin: 30px auto;
text-align: center;
`;
[ App 컴포넌트 ]
const [isModalOpen, setIsModalOpen] = useState()
를 이용해 모달의 열림/닫힘 버튼의 상태를 관리한다.
handleOpenModal함수는 모달을 열기 위해,
handleCloseModal함수는 모달을 닫기 위해 호출된다.
- JSX를 이용해 화면에 컨테이너를 생성하고, 모달이 열려있을 때만
제목(title) / 내용(content)등이 담긴 Modal 컴포넌트를 렌더링한다.

import React from 'react';
const Button = (props) => {
const { text, onClick } = props;
return <button onClick={onClick}>{text}</button>;
};
const Modal = (props) => {
const { title, content, onClose } = props;
return (
<>
<h2>{title}</h2>
<p>{content}</p>
<Button text="Close Modal" onClick={onClose} />
</>
);
};
export default Modal;
[ Modal 컴포넌트 ]
const { title, content, onClose } = props구조 분해 할당을 이용해props객체에서
제목(title) / 내용(content) / 닫기 함수(onClose)속성을 추출해 받아 화면에 렌더링한다.
- 'Close Modal'
text를 가진 Button 컴포넌트를 렌더링하고,
버튼을 클릭 시onClose함수가 호출되도록 설정되었다.
[ Button 컴포넌트 ]
const { text, onClick } = props구조 분해 할당을 이용해props객체에서
텍스트(text) / 열기 함수(onClick)속성을 추출해 받아 화면에 렌더링한다.
- JSX를 이용해 버튼을 생성하고,
onClick함수를 호출한다.
=> 이렇게 각자 기능을 하는 Button / Modal 컴포넌트를 만들어 다른 컴포넌트에서 버튼과 모달을 재사용할 수 있다.

그런데 만약, 여러 개의 비슷한 모달이 필요하다면?
이제 합성 컴포넌트를 적용해 보자!

import React from 'react';
import styled from 'styled-components';
import { createGlobalStyle } from 'styled-components';
import { normalize } from 'styled-normalize';
const GlobalStyle = createGlobalStyle`
${normalize}
button {
width: 70px;
height: 25px;
background: #FFD69D;
border: 1px solid gray;
border-radius: 5px;
margin: 5px;
font-size: 13px;
}
`;
const CardDiv = styled.div`
padding: 20px;
border-radius: 10px;
border: 1px solid #c4c4c4;
background-color: #fcffde;
margin: 30px auto;
width: 200px;
text-align: center;
`;
const CardOne = (props) => {
return (
<>
<CardDiv>
<h3>너의 카드</h3>
<hr />
<button>초기화</button>
<button>저장하기</button>
</CardDiv>
</>
);
};
const CardDivTwo = styled.div`
padding: 20px;
border-radius: 10px;
border: 1px solid #c4c4c4;
background-color: #fcffde;
margin: 30px auto;
width: 500px;
text-align: center;
`;
const CardTwo = (props) => {
return (
<>
<GlobalStyle />
<CardDivTwo>
<h3>나의 카드</h3>
<hr />
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Cumque ut eveniet, laudantium,
deleniti autem sequi molestias magni quia, aliquam et praesentium nostrum dolores culpa
cupiditate unde doloremque labore beatae accusamus.
</p>
<div>
<button>추가하기</button>
<button>저장하기</button>
<button>수정하기</button>
<button>삭제하기</button>
</div>
</CardDivTwo>
</>
);
};
function App() {
return (
<>
<CardOne />
<CardTwo />
</>
);
}
export default App;
// style - width를 제외하고 코드 동일
const CardDiv = styled.div`
padding: 20px;
border-radius: 10px;
border: 1px solid #c4c4c4;
background-color: #fcffde;
margin: 30px auto;
width: 200px;
text-align: center;
`;
// tag 동일
<CardDiv>
<h3></h3>
<hr />
</CardDiv>
import React from 'react';
import styled from 'styled-components';
import { createGlobalStyle } from 'styled-components';
import { normalize } from 'styled-normalize';
const GlobalStyle = createGlobalStyle`
${normalize}
button {
width: 70px;
height: 25px;
background: #FFD69D;
border: 1px solid gray;
border-radius: 5px;
margin: 5px;
font-size: 13px;
}
`;
const CardDiv = styled.div`
padding: 20px;
border-radius: 10px;
border: 1px solid #c4c4c4;
background-color: #fcffde;
margin: 30px auto;
width: ${(props) => (props.className === 'yourCard' ? '300px' : '500px')};
text-align: center;
`;
const Card = (props) => {
return (
<>
<CardDiv className={props.className}>
<h3>{props.value}</h3>
<hr />
</CardDiv>
</>
);
};
const App = () => {
return (
<>
<GlobalStyle />
<Card className="yourCard" value="너의 카드" />
<Card className="myCard" value="나의 카드" />
</>
);
}
export default App;
코드 설명
- Card 컴포넌트를 하나 만들고,
className props로 넘겨준 값으로styled-component의
props조건문을 통해className props값에 따라width가 달리진다.
value props를 사용해h3태그에 들어갈 텍스트를 설정한다.

const YourCard = () => {
return (
<>
<button>초기화</button>
<button>저장하기</button>
</>
);
};
const MyCard = () => {
return (
<>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Cumque ut eveniet, laudantium,
deleniti autem sequi molestias magni quia, aliquam et praesentium nostrum dolores culpa
cupiditate unde doloremque labore beatae accusamus.
</p>
<div>
<button>추가하기</button>
<button>저장하기</button>
<button>수정하기</button>
<button>삭제하기</button>
</div>
</>
);
};
코드 설명
<hr />태그 아래에 들어갈 내용들YourCard, MyCard각각 컴포넌트를 만든다.

const CardDiv = styled.div`
padding: 20px;
border-radius: 10px;
border: 1px solid #c4c4c4;
background-color: #fcffde;
margin: 30px auto;
width: ${(props) => (props.className === 'yourCard' ? '300px' : '500px')};
text-align: center;
`;
const Card = (props) => {
return (
<>
<CardDiv className={props.className}>
<h3>{props.value}</h3>
<hr />
<div>{props.children}</div>
</CardDiv>
</>
);
};
코드 설명
props.children속성을 통해 자식으로 사용되는 부분이 들어가야 하는 곳<hr />태그 아래에 해당 코드를 넣는다.
const App = () => {
return (
<>
<GlobalStyle />
<Card className="yourCard" value="너의 카드">
<YourCard />
</Card>
<Card className="myCard" value="나의 카드">
<MyCard />
</Card>
</>
);
};
코드 설명컴포넌트 사이에 들어가는 자식요소를
props.children으로 받아오게 되면 최종 App 컴포넌트 안에서 위와 같은 방식으로 사용할 수 있다.

import React from 'react';
import styled from 'styled-components';
import { createGlobalStyle } from 'styled-components';
import { normalize } from 'styled-normalize';
const GlobalStyle = createGlobalStyle`
${normalize}
button {
width: 70px;
height: 25px;
background: #FFD69D;
border: 1px solid gray;
border-radius: 5px;
margin: 5px;
font-size: 13px;
}
`;
const CardDiv = styled.div`
padding: 20px;
border-radius: 10px;
border: 1px solid #c4c4c4;
background-color: #fcffde;
margin: 30px auto;
width: ${(props) => (props.className === 'yourCard' ? '300px' : '500px')};
text-align: center;
`;
const Card = (props) => {
return (
<>
<CardDiv className={props.className}>
<h3>{props.value}</h3>
<hr />
<div>{props.children}</div>
</CardDiv>
</>
);
};
const YourCard = () => {
return (
<>
<button>초기화</button>
<button>저장하기</button>
</>
);
};
const MyCard = () => {
return (
<>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Cumque ut eveniet, laudantium,
deleniti autem sequi molestias magni quia, aliquam et praesentium nostrum dolores culpa
cupiditate unde doloremque labore beatae accusamus.
</p>
<div>
<button>추가하기</button>
<button>저장하기</button>
<button>수정하기</button>
<button>삭제하기</button>
</div>
</>
);
};
const App = () => {
return (
<>
<GlobalStyle />
<Card className="yourCard" value="너의 카드">
<YourCard />
</Card>
<Card className="myCard" value="나의 카드">
<MyCard />
</Card>
</>
);
};
export default App;