React Component 가변적으로 생성/추가하기, 제거하기 (Alert 가변 생성 예시 포함)
* 컴포넌트 동적으로 생성/추가(가변적으로 생성)하는 코드만 필요한 경우 앞 Alert 코드는 넘어가도록 하자.
회원가입 및 로그인 기능을 구현하다 보니 로그인, 회원가입에 대한 Alert이 필요했다.
(성공, 실패 여부. 에러 및 실패에 대한 사유 등 알림을 띄워주기 위해 필요.)
Alert Component를 하나 만들고 로그인 및 회원가입 API Response에 따라 Alert을 가변적으로 생성하려고 한다.
우선 Alert 코드를 다음과 같이 생성하였다.
Alert.js
import style from '../../style/component/Alert.module.css'
import React, { useRef, useEffect } from 'react';
/**
* [Alert]
* @param alertType {String} "success", "warning", "error" 중 택 1, 지정하지 않거나 다른 값을 넣는 경우 일반 테마 적용됨
* @param contents {String} Alert 내용
* @param duration {Number} Alert 자동 종료 시간(Sec), 값이 없는 경우 종료하지 않음
* @returns {Element}
*/
const Alert = ({alertType, contents, duration}) => {
// Alert style을 가변적으로 지정하기 위해 사용
let styleType;
// Dom 선택을 위해 Ref 생성
const alertRef = useRef(null);
// Alert style 지정
styleType = `${style.alertContainer} `;
if(alertType === 'success') { styleType = styleType + `${style.success}`; }
else if(alertType === 'warning') { styleType = styleType + `${style.warning}`; }
else if(alertType === 'error') { styleType = styleType + `${style.error}`; }
else { styleType = styleType + `${style.normal}`; }
/**
* [Alert 제거]
* - Alert Component에서 parameter로 duration을 받은 경우 duration 이후 자동 종료됨.
* - duration에 상관없이 x 아이콘을 눌렀을 때 또한 종료됨.
*/
const closeAlert = () => {
const elementToRemove = alertRef.current;
// duration 이전에 alert 종료 버튼을 먼저 누르는 경우 해당 노드가 없어 에러가 발생하여 조건문 추가
if (elementToRemove && elementToRemove.parentNode) {
elementToRemove.parentNode.removeChild(elementToRemove);
}
};
useEffect(() => {
if (duration) {
/**
* setTimeout으로 duration 타임 이후 해당 alert 제거하는 함수 호출
* duration : 자동 종료 시간, 단위 Sec로 자동 변경
*/
const timeoutId = setTimeout(() => {
closeAlert();
}, duration * 1000);
return () => clearTimeout(timeoutId);
}
}, [duration]);
return (
<div className={styleType} ref={alertRef}>
{/* Contents */}
<div>
<label>
{contents}
</label>
</div>
{/* X button */}
<div onClick={closeAlert}>
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" focusable="false" viewBox="0 0 12 12" aria-hidden="true">
<path stroke="currentColor" strokeLinecap="round" d="M3 9l6-6m0 6L3 3"></path>
</svg>
</div>
</div>
);
};
export default Alert;
Alert.module.css
.alertContainer {
display: flex;
align-items: center;
justify-content: space-between;
padding-inline: 10px;
padding-block: 8px;
box-sizing: border-box;
width: 100%;
border-radius: 8px;
margin-bottom: 5px;
}
.success {
background-color: rgb(237, 248, 244);
border: 1px solid rgb(89 184 147);
color: rgb(24, 97, 70);
}
.warning {
background-color: rgb(255, 247, 237);
border: 1px solid rgb(254, 214, 168);
color: rgb(173, 89, 24);
}
.error {
background-color: rgb(255, 240, 241);
border: 1px solid rgb(245, 181, 186);
color: rgb(140, 35, 44);
}
.normal {
background-color: rgb(248, 249, 249);
border: 1px solid rgb(216, 220, 222);
color: rgb(104, 115, 125)
}
그리고 해당 Alert Component를 동적으로 생성이 필요한 곳으로 이동하여 다음과 같이 사용해보자.
LoginPage.js (나는 여기서 Alert을 생성하고자 함)
// ... LoginPage 코드 생략
// Alert
const [alerts, setAlerts] = useState([]);
const addAlert = (alertType, contents, duration) => {
const newAlert = <Alert
key={alerts.length}
alertType={alertType}
contents={contents}
duration={duration}
/>;
setAlerts([...alerts, newAlert]);
}
// ...LoginPage 코드 생략
// API 호출 후 Response를 받는 부분...
addAlert('warning', response.data.message, 3);
// API 예외처리 부분...
} catch(error) {
addAlert('error', error, 3);
}
// ... LoginPage 코드 생략
return (
<div className={style.backgroundContainer}>
{/* alert을 넣어 줄 Container */}
<div className={style.alertStackContainer}>
{alerts.map((alert, index) => (
<div key={index}>{alert}</div>
))}
</div>
// ... 이후 코드 생략
LoginPage.module.css
/* 그 외 css 생략 */
.alertStackContainer {
position: absolute;
right: 10px;
top: 10px;
display: flex;
flex-direction: column;
width: 500px;
border-radius: 10px;
z-index: 1;
}
useState로 alerts 배열을 생성하고 addAlert 함수를 통해 Alert Component를 저장한다.
LoginPage를 구성하고 return해 주는 부분에 Alert을 띄워줄 공간을 만들어 두었다. (alertStackContainer)
{alerts.map((alert, index) => (
<div key={index}>{alert}</div>
))}
위와 같이 useState로 관리되는 alerts를 출력해 준다.
useState에 대한 개념이 부족하다면 하단 게시물을 참고하자.
https://seokbong.tistory.com/243
React Hooks 간단 정리
useState - 현재 상태를 나타내는 state와 state를 변경하는 setState를 한 쌍으로 제공 - state의 초기값 설정 가능, 첫 렌더링 때 한번 사용 useEffect - useEffect(function, deps) 형태로 사용 - function은 실행시킬
seokbong.tistory.com
관련 게시물
https://seokbong.tistory.com/253