skip to Main Content

While i am using react-native-toast-notifications in react native project, i have used useToast() in my splashscreen.

I have wrapped splashscreen component using ToastProvider

Here is it

import { DefaultTheme, NavigationContainer } from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import { SplashScreen } from '@pages/auth/splash'
import { SignIn } from '@pages/auth/login'
import { ToastProvider } from 'react-native-toast-notifications'

const RootStack = createNativeStackNavigator()
const navigationContainerTheme = DefaultTheme
navigationContainerTheme.colors.background = color.appBackgroudColor

export const Routing = () => {
    return (
        <ToastProvider>
            <MenuProvider>
                <NavigationContainer theme={navigationContainerTheme}>
                    <RootStack.Navigator
                        initialRouteName={Routes.SPLASH}
                        screenOptions={{ animation: 'none' }}
                    >
                        <RootStack.Screen
                            name={Routes.SIGN_IN}
                            component={SignIn}
                            options={{
                                headerShown: false,
                            }}
                        />
                    </RootStack.Navigator>
                </NavigationContainer>
            </MenuProvider>
        </ToastProvider>
    )
}

And here is my splashscreen.ts file

import React, { useEffect } from 'react'
import {
    ScrollView,
    StyleSheet,
    useColorScheme,
    View,
    TouchableOpacity,
} from 'react-native'
import { SplashScreenProps } from '@app/types'
import { Routes } from '@shared/config/routes'
import { sendPing } from '@shared/api/defaultApi'
import { useToast } from 'react-native-toast-notifications'

export const SplashScreen = ({ navigation }: SplashScreenProps) => {
    const css = styleInit(useColorScheme() === 'dark')
    const toast = useToast()

    useEffect(() => {
        showSplashScreen()
    }, [navigation])

    const showSplashScreen = async () => {
        const pingResponse = await sendPing()
        if (pingResponse) {
            toast.show('Success to connect server!')
            navigation.navigate(Routes.AUTHORIZE)
        } else {
            toast.show('Failed to connect server!')
            console.log('Ping server failed!')
        }
    }

    return (
        <View>
            <Text>Splashscreen</Text>
        </View>
    )
}

And if i start the app, it will send a ping to server and get the response.
And after i get the response, this error has occurred

Possible unhandled promise rejection (id: 0: TypeError: toast.show is not a function (it is undefined)
...

I dont know what the reason is, maybe there is delay to initialize the toast using useToast() hook?
I would appreciate it if someone could help me with this problem.
Thanks.

I have tried to set the timeout till the toast is initialized, but it didnt work as well.

2

Answers


  1. From looking at the react-native-toast-notifications GitHub issues, this may be caused by a recent-ish bug where the toast is attempted to be loaded before the application renders.

    Someone created this override of the ToastProvider component that may solve the issue for you if you use it instead of the imported ToastProvider.

    export const ToastProvider: FC<PropsWithChildren> = ({children}) => {
      const toastRef = useRef(null);
      const [refState, setRefState] = useState(null);
    
      useEffect(() => {
        setRefState(toastRef.current as any);
        GlobalToast = toastRef.current as any;
      }, []);
    
      return (
        <ToastContext.Provider value={refState as any}>
          <Toast` ref={toastRef} />
          {refState && children}
        </ToastContext.Provider>
      );
    };
    
    Login or Signup to reply.
  2. You should wait until Toast component is rendered, which can be done using useEffect.

    useEffect(() => {
        const initializeToast = async () => {
            while (!toast || !toast.show) {
                await new Promise(resolve => setTimeout(resolve, 100))
            }
            isToastInitialized.current = true
            showSplashScreen()
        }
        initializeToast()
    }, [toast])
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search