Redux와 React Hooks를 활용하여 토스트 구현
15804 단어 ToastreacthooksReactredux
사용자에게 뭔가 내용을 일시적으로 전달하고 싶을 때가 있다고 생각합니다.
그러한 때에 사용되는 통지의 UI의 일종인 토스트를 구현해 갑니다.
이미지로서는 이런 것입니다
토스트 요구 사항
아래의 요건을 충족하는 토스트를 만들어 갑니다.
구현
1. 토스트 정보를 보관할 장소를 준비합니다.
어디서나 추가하고 참조할 수 있도록 Redux의 Store에 가져가십시오.
Store 자체의 설정에 대해서는 생략합니다.
// toast.ts
import { Reducer, AnyAction } from 'redux'
import { isType, actionCreatorFactory } from 'typescript-fsa'
import { useSelector } from 'react-redux'
export type Toast = {
message: string
}
type Toasts = Toast[]
// action
const actionCreator = actionCreatorFactory('TOAST')
export const Push = actionCreator<{ toast: Toast }>('PUSH')
export const Shift = actionCreator('SHIFT')
// reducer
const initialState: Toasts = []
export const reducer: Reducer<Toasts> = (
state: Toasts = initialState,
action: AnyAction,
) => {
if (isType(action, Push)) {
const { toast } = action.payload
return state.concat([toast])
}
if (isType(action, Shift)) {
return state.slice(1)
}
return state
}
export default reducer
// selector
export const GetToasts = (): Toasts => useSelector(
(state: { toasts: Toasts }) => state.toasts,
)
State는 파일에 정의되어 있습니다.
프로젝트에 맞게 로드하면 좋다고 생각합니다.
2. 토스트를 표시하는 구성 요소 준비
이 컴퍼넌트에서는 표시 상태를 관리하기 위해서 useState
토스트의 변화를 모니터링하기 위해 useEffect
와 같은 React Hooks 기능을 사용합니다.
토스트의 정보는 Store에 저장하고 selector도 준비되어 있기 때문에
어디서나 쉽게 호출할 수 있습니다.
// ToastContainer.tsx
import React, { useState, useEffect } from 'react'
import { useDispatch } from 'react-redux'
import { GetToasts, Shift } from 'toast.ts'
import style from 'style.scss'
const timeout = async (ms: number) => (
new Promise((resolve: () => void): void => {
setTimeout(() => resolve(), ms)
})
)
const ToastContainer: React.FC = () => {
const toasts = GetToasts()
const [visible, setVisible] = useState(false)
const dispatch = useDispatch()
useEffect(() => {
if (toasts.length === 0 || visible) {
return
}
const showToast = async () => {
setVisible(true)
await timeout(3000)
setVisible(false)
await timeout(500)
dispatch(Shift())
}
showToast()
}, [toasts])
return (
<div className={style.toastContainer}>
<div className={`${style.toast} ${visible && style.visible}`}>
{toasts.length > 0 && toasts[0].message}
</div>
</div>
)
}
export default ToastContainer
토스트의 표시 흐름은 다음과 같습니다.
// toast.ts
import { Reducer, AnyAction } from 'redux'
import { isType, actionCreatorFactory } from 'typescript-fsa'
import { useSelector } from 'react-redux'
export type Toast = {
message: string
}
type Toasts = Toast[]
// action
const actionCreator = actionCreatorFactory('TOAST')
export const Push = actionCreator<{ toast: Toast }>('PUSH')
export const Shift = actionCreator('SHIFT')
// reducer
const initialState: Toasts = []
export const reducer: Reducer<Toasts> = (
state: Toasts = initialState,
action: AnyAction,
) => {
if (isType(action, Push)) {
const { toast } = action.payload
return state.concat([toast])
}
if (isType(action, Shift)) {
return state.slice(1)
}
return state
}
export default reducer
// selector
export const GetToasts = (): Toasts => useSelector(
(state: { toasts: Toasts }) => state.toasts,
)
// ToastContainer.tsx
import React, { useState, useEffect } from 'react'
import { useDispatch } from 'react-redux'
import { GetToasts, Shift } from 'toast.ts'
import style from 'style.scss'
const timeout = async (ms: number) => (
new Promise((resolve: () => void): void => {
setTimeout(() => resolve(), ms)
})
)
const ToastContainer: React.FC = () => {
const toasts = GetToasts()
const [visible, setVisible] = useState(false)
const dispatch = useDispatch()
useEffect(() => {
if (toasts.length === 0 || visible) {
return
}
const showToast = async () => {
setVisible(true)
await timeout(3000)
setVisible(false)
await timeout(500)
dispatch(Shift())
}
showToast()
}, [toasts])
return (
<div className={style.toastContainer}>
<div className={`${style.toast} ${visible && style.visible}`}>
{toasts.length > 0 && toasts[0].message}
</div>
</div>
)
}
export default ToastContainer
toasts
가 늘어나면 감시하고 있다 useEffect
가 발화 visible
를 true
로 변경 visible
를 false
로 변경하고 숨기기dispatch(Shift())
에서 첫 번째 toasts
제거 toasts
가 업데이트되기 때문에 useEffect
가 다시 발화 toasts
있다면 2로 돌아갑니다 그리고는 적절하게 CSS를 맞추면 괜찮습니다.
// style.scss
.toast {
width: 320px;
padding: 16px 0;
color: #fff;
text-align: center;
background-color: red;
opacity: 0;
transition: opacity .6s;
&.show {
opacity: 1;
transition: opacity .2s;
}
}
3. 토스트 추가
Redux에서 토스트를 관리하기 때문에 어디에서 추가해도 괜찮습니다.
예를 들어 뭔가 API를 부르면 이렇게 토스트를 추가합니다.
save()
.then(() => dispatch(Push({ toast: { message: '保存しました' } })))
.catch(() => dispatch(Push({ toast: { message: '保存に失敗しました' } })))
토스트의 내용에 따라 색을 바꾸거나 하고 싶은 경우는
type
등도 갖게 합시다.요약
밸리데이션이나 표시의 방법에 관해서는 실장하고 싶은 사양에 맞추어 적절히 변경해 주세요.
React Hooks를 사용하면 번잡했던 처리가 깔끔하게 쓸 수 있으므로 즐겁습니다.
참고
Reference
이 문제에 관하여(Redux와 React Hooks를 활용하여 토스트 구현), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/sesta/items/24c95529ecb2aa59b97b텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)