timolins / react-hot-toast

Smoking Hot React Notifications 🔥
https://react-hot-toast.com
MIT License
9.84k stars 331 forks source link

Property 'document' doesn't exist || Cannot read property 'useToaster' of undefined. React Native #317

Open CandresFelipe opened 1 year ago

CandresFelipe commented 1 year ago

I am trying to implement in my new project react-hot-toast and following the [example](https://snack.expo.dev/@timo/react-hot-toast---usetoaster()---react-native) in how implement in RN, I found this issue by simply add in a onPress a toast.

                    <View style={tw`flex-1 justify-end bottom-5`}>
                        <Button title="Login" isHighlight onPress={() => toast("hello!")} />
                    </View>

I tried by using the useToaster() hook but have some type error that if I can ignore it, the document doesn't exists error shows up.

timolins commented 1 year ago

You can can try to import useToaster() from react-hot-toast/headless, which should not rely on `document.

import { useToaster } from "react-hot-toast/headless"

The import in the example is wrong, as the correct import doesn't work in the Expo Snack.

CandresFelipe commented 1 year ago

Oh yeah, you right, I could remove that error, however trying to adapt that example into my project, I can't see displayed any Toast.

here is the code snippet:


interface ToastPrimitiveProps2 {
    bgColor: Style
    onPress?: () => void
    text1: string
    text2: string
    t: ToastInterface
    offset: number
    updateHeight: (heightId: string, height: number) => void
}

const Message = ({
    text1,
    text2,
    textColorStyle
}: {
    text1: string
    text2: string
    textColorStyle: string
}) => (
    <View style={tw`flex flex-row justify-evenly`}>
        <Text
            style={tw`self-center font-sans text-base font-bold ${textColorStyle}`}>
            {text1}
        </Text>
        <Text style={tw`text-sm ${textColorStyle}`}>{text2}</Text>
    </View>
)

const ToastPrimitive2: FunctionComponent<ToastPrimitiveProps2> = ({
    bgColor,
    t,
    text1,
    text2,
    onPress,
    offset,
    updateHeight
}) => {
    // Animations for enter and exit
    const fadeAnim = useRef(new Animated.Value(0.5)).current
    const posAnim = useRef(new Animated.Value(-80)).current

    console.log("this is rendered")
    useEffect(() => {
        Animated.timing(fadeAnim, {
            toValue: t.visible ? 1 : 0,
            duration: 300,
            useNativeDriver: false
        }).start()
    }, [fadeAnim, t.visible])

    useEffect(() => {
        Animated.spring(posAnim, {
            toValue: t.visible ? offset : -80,
            useNativeDriver: false
        }).start()
    }, [posAnim, offset, t.visible])

    const textColorStyle =
        t.type !== "error" ? "text-petrol-100" : "text-petrol-900"
    return (
        <Animated.View
            style={tw.style(
                "flex flex-col w-full p-3 rounded-x ",
                bgColor,
                t.visible ? "z-[99999]" : undefined,
                ` transform translate-y-[${posAnim}] opacity-[${fadeAnim}]`
            )}>
            <View
                style={tw`flex flex-col justify-evenly`}
                onLayout={(event) =>
                    updateHeight("1", event.nativeEvent.layout.height)
                }>
                <Message text1={text1} text2={text2} textColorStyle={textColorStyle} />
                <Pressable
                    style={tw`self-auto bg-transparent `}
                    onPress={() => onPress?.()}>
                    {t.type !== "success" ? (
                        <IconAngleRight
                            color={tw.color(
                                t.type === "error" ? "bg-petrol-900" : "bg-petrol-100"
                            )}
                        />
                    ) : (
                        <IconClose color={tw.color("bg-petrol-100")} />
                    )}
                </Pressable>
            </View>
        </Animated.View>
    )
}

export const ToastNotification = () => {
    const { toasts, handlers } = useToaster()

    return (
        <View style={tw`absolute top-0 bottom-0 left-0 right-0`}>
            {toasts.map((t) => (
                <ToastPrimitive2
                    key={t.id}
                    bgColor={tw.style({
                        "bg-feedbackColors-success": t.type === "success",
                        "bg-feedbackColors-error": t.type === "error",
                        "bg-feedbackColors-warning": t.type === "blank"
                    })}
                    text1="hello"
                    text2="description"
                    t={t}
                    updateHeight={(heightId, height) =>
                        handlers.updateHeight(t.id, height)
                    }
                    offset={handlers.calculateOffset(t, {
                        reverseOrder: false
                    })}
                />
            ))}
        </View>
    )
}

When usage:

<View style={tw`flex-1 justify-end bottom-5`}>
                        <Button
                            title="Login"
                            isHighlight
                            onPress={() =>
                                toast.success("hello", {
                                    position: "top-center"
                                })
                            }
                        />
                    </View>