Created
May 19, 2020 06:24
-
-
Save daphnesmit/8d7aad4b830f254648092b31f86fa2de to your computer and use it in GitHub Desktop.
Toast Context for React with Typescript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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