Skip to content

Instantly share code, notes, and snippets.

@daphnesmit
Created May 19, 2020 06:24
Show Gist options
  • Save daphnesmit/8d7aad4b830f254648092b31f86fa2de to your computer and use it in GitHub Desktop.
Save daphnesmit/8d7aad4b830f254648092b31f86fa2de to your computer and use it in GitHub Desktop.
Toast Context for React with Typescript
export type AlertType = 'warning' | 'neutral' | 'success'
export interface Toast {
content: string
id: number
type: AlertType
}
interface ActionAdd {
type: 'ADD'
toast: Toast
}
interface ActionRemove {
type: 'REMOVE'
id: number
}
type Action = ActionAdd | ActionRemove
type State = Toast[]
export const reducer = (state: State, payload: Action) => {
switch (payload.type) {
case 'REMOVE':
const newState = state.filter((t: Toast) => t.id !== payload.id)
return newState
case 'ADD':
return [...state, payload.toast]
default:
return state
}
}
import React, { FC, useCallback, useContext, useMemo, useReducer } from 'react'
import { AlertType, reducer, Toast } from './reducer'
interface ToastProviderProps {
navCollapsed?: boolean
}
interface AddToastProps {
content: string
type: AlertType
timeout?: number
}
export interface ToastContextStore {
add: (props: AddToastProps) => void
remove: (id: number) => void
toasts: Toast[]
}
let toastCount = 0
const toastTimeout = 3000
export const ToastContext = React.createContext({} as ToastContextStore)
export const ToastContextConsumer = ToastContext.Consumer
export function useToasts() {
const context = useContext(ToastContext)
if (context === undefined) {
throw new Error(`useToasts must be used within a ToastProvider`)
}
return context
}
export const ToastProvider: FC<ToastProviderProps> = props => {
const [toasts, dispatch] = useReducer(reducer, [])
const remove = useCallback((id: number) => {
dispatch({ type: 'REMOVE', id })
}, [])
const add = useCallback(
({ content, type, timeout = toastTimeout }: AddToastProps) => {
const id = toastCount++
const toast = { content, id, type }
dispatch({ type: 'ADD', toast })
if (timeout) {
setTimeout(() => remove(id), timeout)
}
},
[remove],
)
const store: ToastContextStore = useMemo(
() => ({
add,
remove,
toasts,
}),
[add, remove, toasts],
)
return <ToastContext.Provider {...props} value={store} />
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment