Today Mini Learned :

기록하는 습관 들이기

STUDY - 공부기록/Web

[React] 리액트에서 toast 알림창 직접 만들어보기

얌챠 2021. 9. 18. 04:15

React로 웹 앱을 만들 때, 입력하지 않은 input이 있으면 알림을 띄우는 기능을 구현하려고 했다.
이 때 alert 대신 toast를 통해 알림을 띄우면 깔끔해 보일 것 같아 만들어보는 toast 알림창!

 

❕ Toast Notification

"알라미" 앱에서의 toast 알림

이런 알림이 toast알림이다. 안드로이드에서 자주 보이는 알림인데, 웹에서는 내장되어 있는 기본 기능이 아니기 때문에 직접 만들어야 한다.

 

+ react-toastify라는 오픈 소스 라이브러리를 이용하여 간단하고 쉽게 toast 알림 기능을 사용할 수 있게 코드를 제공하고 있었다. 하지만 나는 직접 만들어 보고 싶은 생각이 있어서(...!!) 이번만 만들어보고 다음부터는 저 오픈소스를 사용한 알림도 구현해보고 싶다.

 


 

💫 구현 과정

1. 기능 구상

위의 react-toastify의 기능을 참고해서 생각해봤다.
* 하단 왼쪽에 fixed로 위치를 잡아서 띄워 줄 것
* 빨간색 계열 반투명 알림 (경고니까!)
* 클릭시/또는 시간이 지나면 자동으로 사라짐(약 3초?)
* 등장 시 올라오는 애니메이션, 사라질 때도 내려가는 애니메이션

 

2. 컴포넌트 작성

import React, { useState, useEffect } from "react";

// css
import "./Toast.css";

function ToastNotification() {
    

    return (
        <div className="toast-alert">
            <img alt="" src="img/alert.png" />
            <p>입력하지 않은 칸이 있습니다!</p>
        </div>
    );
}

export { ToastNotification }

다음과 같이 ToastNotification.js라는 파일을 만들고 따로 컴포넌트를 작성해 보았다.

사용할 때에는 import한 뒤 다음과 같이 넣어주면 끝!

import {ToastNotification} from "./ToastNotification.js";

...

<ToastNotification/>

이렇게 기본 틀을 만들었다. 이제 여기에 CSS로 디자인을 입히고, 애니메이션과 사라지는 이벤트를 추가해 줄 것이다.

 

3. CSS로 꾸며주기

.toast-alert {
  background-color: rgba(255, 127, 80, 0.4);
  border: 1px solid rgba(255, 127, 80, 0.1);
  border-radius: 10px;
  box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 15%);
  height: 40px;
  width: 250px;
  padding: 5px;
  text-align: center;
  font-size: 1.5rem;
  font-weight: bold;
  color: black;
  display: flex;
  align-items: center;
  justify-content: center;
  position: fixed;
  bottom: 20px;
  left: 20px;
}

.toast-alert img {
  width: 25px;
  height: auto;
  margin-right: 10px;
}

.toast-alert p {
  margin: 0;
}

그냥 그럴듯하게 작성해 본 toast 알림창

짠 생각보다 귀여움ㅎ 맘에 든당😁

여기까지는 그냥 일반적인 구성 요소 만드는 느낌이라 빨리 넘어갔다!

 

4. state와 useEffect를 이용해 이벤트 발생 시 띄우고, 시간 지나면 사라지게 구현

먼저 toastState라는 state를 하나 만들 것이다. 이 state는 toast 알림창의 상태를 저장해 둘 state이다. 기본값을 false로 두고, 특정 이벤트를 통해 true로 만들면 toast 알림창의 등장과 사라짐을 구현할 수 있다.
(여기서 특정 이벤트란? 지금 만들려는 toast 알림창의 경우에는 input이 전부 입력되지 않았을 때! 즉 알림창이 등장해야 할 이벤트)

그래서 toastState가 true가 되면 ToastNotification 컴포넌트를 보여주고, 이때 ToastNotification의 useEffect가 실행된다. useEffect에서는 js의 setTimeout기능을 이용한 timer를 통해 특정 시간 동안 기다렸다가 다시 toastState를 false로 바꿔 준다. 그러면 ToastNotification 컴포넌트가 다시 보이지 않게 될 것이다.

 

이를 구현한 코드는 다음과 같다

// ToastNotification.js
import React, { useState, useEffect } from "react";

// css
import "./Toast.css";

function ToastNotification(props) {
    useEffect(() => {
        let timer = setTimeout(() => {
            props.setToastState(false);		// 2초 뒤, toastState가 false가 되면서 알림창이 사라진다
        }, 2000);

        return () => { clearTimeout(timer) }
    }, []);

    return (
        <div className="toast-alert">
            <img alt="" src="img/alert.png" />
            <p>입력하지 않은 칸이 있습니다!</p>
        </div>
    );
}

export { ToastNotification }
// Page.js
let [toastState, setToastState] = useState(false);

function checkInputValues() {
	// checkInputValues : 입력하지 않은 input값이 있으면 해당 칸으로 이동시켜주고 toast알림을 통해 입력하지 않은 칸이 있다고 알리는 함수
	if (inputData.userName === "") {
		setUserInputScreen(0);
		setToastState(true);
		return false;
	}
	return true;
}

...

{
	toastState === true ? (
		<ToastNotification setToastState={setToastState} />
	) : null
}

 

5. 등장/사라질 때 애니메이션 추가

무미건조하게 사라지고 나타나는 건 많이 해 봤으니 애니메이션도 넣어보려 한다

@keyframes slideIn {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(0%);
  }
}

@keyframes slideOut {
  from {
    transform: translateX(0%);
  }
  to {
    transform: translateX(-300%);
  }
}

.openAnimation {
  animation: slideIn 0.5s ease-in-out 0s 1 normal forwards;
}

.closeAnimation {
  animation: slideOut 0.5s ease-in-out 0s 1 normal forwards;
}

keyframes를 만들고, 클래스에 적용할 애니메이션도 만들어 두었다.

 

이벤트의 적용은 ToastNotification의 클래스를 조정하는 방식으로 했는데,

let [toastAnimation, setToastAnimation] = useState("toast-alert");

다음과 같이 toast 알림창의 class를 저장해둘 state를 만들고,

function ToastNotification(props) {
    useEffect(() => {

        let timer2;
        let timer = setTimeout(() => {
            props.setToastAnimation("toast-alert closeAnimation");
            timer2 = setTimeout(() => {
                props.setToastState(false);
            }, 500);
        }, 3000);

        return () => {
            clearTimeout(timer);
            clearTimeout(timer2);
        }
    }, []);

    return (
        <div className={props.toastAnimation}>
            <img alt="" src="img/alert.png" />
            <p>입력하지 않은 칸이 있습니다!</p>
        </div>
    );
}

처음 ToastNotification이 열릴 때(ToastState가 true가 될 때) openAnimation 클래스를 넣어 준 뒤, 3초 동안 타이머를 통해 시간을 잰다. (해당 알림이 보여지는 시간이 3초이다)

시간이 지나면 알림을 사라지게 해야 하므로, openAnimation 클래스가 없어지고 closeAnimation 클래스가 적용된다. 애니메이션의 duration은 0.5초여서 0.5초 동안 애니메이션이 실행되고 다시 timer2를 통해 ToastNotification이 사라질 수 있도록 state를 변경했다.

 

6. 클릭 이벤트 추가

이제 클릭해서 사라지도록 하는 이벤트도 추가해 준다.

function toastClickEvent() {
	props.setToastState(false);
}

함수를 하나 만들어 toast의 state를 바로 변경해주도록 한다.

<div className={props.toastAnimation} onClick={() => { toastClickEvent() }}>
	<img alt="" src="img/alert.png" />
	<p>입력하지 않은 칸이 있습니다!</p>
</div>

그 다음 toast의 onClick 이벤트에 해당 함수를 추가하면 끝!

 


 

✨ 결과

만든 입력 창 알림은 다음과 같다!