Reputation: 6810
Trying to use react-toastr in my react/TS app. But the example provided (https://tomchentw.github.io/react-toastr/) does not work.
I import like this:
import { ToastContainer, ToastMessageAnimated } from "react-toastr";
And use like this:
class RegistrationSelectionPage extends React.Component<{}, {}> {
public render() {
let container: ToastContainer | null;
return (
<section className="RegistrationSelectionPage">
<ToastContainer
ref={ref => container = ref}
className="toast-top-right"
toastMessageFactory={ToastMessageAnimated}
/>
<button onClick={() => container && container.warning('No connection', 'Error!')}>Click me</button>
...
I get this error:
Uncaught TypeError: Cannot call a class as a function
at ./node_modules/babel-runtime/helpers/classCallCheck.js.exports.default
...
Which function should I call on ToastMessageAnimated
?
Please provide a complete working example, thanks :)
Upvotes: 0
Views: 1668
Reputation: 4502
The @types are incorrect and look like they have allowed any
for toastMessageFactory
prop to get around a misunderstanding of the correct types, leading to all kinds of confusion
From the docs it expects a React factory function https://tomchentw.github.io/react-toastr/#toastmessage
The default is React.createFactory(ToastMessageAnimated)
which is a factory function created from a Component class defined in the lib. This does serve your current purpose, but the current defs force you to specify it, and accepts any
which defeats the point entirely idea, so lets look into fixing the defs
From the default value we can deduce the type of the toastMessageFactory
should be React.Factory<ToastMessageProps>
which is a factory for one of the component classes from the lib that has the basic ToastMessageProps
Looking up the props and the components in the source code (happily written with Flow so this becomes much easier) we can improve the @type/react-toastr
defs as...
import { Component, ReactHTML, Factory, ReactNode } from 'react'
export interface ToastContainerProps {
toastType?: IconClassNames
id?: string
preventDuplicates?: boolean
toastMessageFactory?: Factory<ToastMessageProps>
newestOnTop?: boolean
onClick?: Function
}
export class ToastContainer extends Component<ToastContainerProps> {
error: <P extends ToastMessageProps>(message: ReactNode, title: ReactNode, optionsOverride?: Partial<P>) => void
info: <P extends ToastMessageProps>(message: ReactNode, title: ReactNode, optionsOverride?: Partial<P>) => void
success: <P extends ToastMessageProps>(message: ReactNode, title: ReactNode, optionsOverride?: Partial<P>) => void
warning: <P extends ToastMessageProps>(message: ReactNode, title: ReactNode, optionsOverride?: Partial<P>) => void
clear: () => void
}
export interface IconClassNames {
error: string
info: string
success: string
warning: string
}
export interface ToastMessageProps {
className?: string,
type: string,
iconClassNames?: IconClassNames,
iconClassName?: string,
closeButton?: boolean,
onCloseClick?: Function,
title?: any,
titleClassName?: string,
message?: any,
messageClassName?: string
}
export interface ToastMessageAnimatedProps extends ToastMessageProps {
className?: string,
showAnimation?: string,
hideAnimation?: string,
timeOut?: number,
extendedTimeOut?: number,
tapToDismiss?: boolean,
onRemove: Function,
onClick?: Function,
onCloseClick?: Function,
}
export interface ToastMessageQueryProps extends ToastMessageProps {
style?: object,
showMethod?: string,
showDuration?: number,
showEasing?: string,
hideMethod?: string,
hideDuration?: number,
hideEasing?: string,
timeOut?: number,
extendedTimeOut?: number,
tapToDismiss?: boolean,
onRemove: Function,
onClick?: Function,
onCloseClick?: Function,
}
export class ToastMessageAnimated extends Component<ToastMessageAnimatedProps> {}
export class ToastMessageQuery extends Component<ToastMessageQueryProps> {}
You can now use these properly typed in your own component...
import {
ToastContainer,
ToastMessageAnimated,
ToastMessageAnimatedProps // import this too for stricter typing of factory
} from "react-toastr"
//... all exactly same as your example, except...
<ToastContainer ref={ref => container = ref}
toastMessageFactory={React.createFactory<ToastMessageAnimatedProps>(ToastMessageAnimated)}
/>
<button onClick={() => container && container.warning<ToastMessageAnimatedProps>('No connection', 'Error!', {className: 'toast-top-right'})}>Click me</button>
Here we are also strictly typing the options for the warning, and setting the className
in it (this was set incorrectly as a container prop, so would not have been applied)
This also now allows you to pass JSX components as message and title too
container.warning<ToastMessageAnimatedProps>(<div>No connection</div>, <h1>Error!</h1>, {className: 'toast-top-right'})
Upvotes: 1