Promise toasts provide a seamless way to show loading states that automatically transition to success or error based on your async operation’s result. Perfect for API calls, file uploads, and any asynchronous task.
Basic usage
The toast.promise() method takes a promise and message configuration for each state:
import { toast } from 'react-native-bread' ;
const fetchUser = async ( id : string ) => {
const response = await fetch ( `/api/users/ ${ id } ` );
return response . json ();
};
toast . promise ( fetchUser ( '123' ), {
loading: { title: 'Loading user...' },
success: { title: 'User loaded!' },
error : ( err ) => ({ title: 'Failed to load user' , description: err . message }),
});
Loading state appears
A loading toast is shown immediately with a spinner icon
Promise settles
The toast automatically updates when your promise resolves or rejects
Final state displays
Success (green checkmark) or error (red X) replaces the loading toast
Message configuration
Each state accepts either a string or an object with title, description, and duration:
Simple strings
Full configuration
toast . promise ( apiCall (), {
loading: 'Saving...' ,
success: 'Saved!' ,
error: 'Failed to save' ,
});
Error handling
The error message can be a static value or a function that receives the error:
toast . promise ( deleteItem ( id ), {
loading: 'Deleting...' ,
success: 'Item deleted' ,
// Function receives the error and can customize the message
error : ( err ) => {
if ( err . message . includes ( 'permission' )) {
return {
title: 'Permission denied' ,
description: 'You don \' t have access to delete this item' ,
};
}
return {
title: 'Failed to delete' ,
description: err . message ,
};
},
});
The error callback receives an Error object. If your promise rejects with a non-Error value, it will be wrapped in an Error automatically.
Return value
The toast.promise() method returns a promise that resolves with a result object:
const result = await toast . promise ( fetchData (), {
loading: 'Loading...' ,
success: 'Done!' ,
error: 'Failed' ,
});
if ( result . success ) {
console . log ( 'Data:' , result . data );
} else {
console . error ( 'Error:' , result . error );
}
Type signature
interface PromiseResult < T > {
data ?: T ;
error ?: Error ;
success : boolean ;
}
When success is true, data contains the promise’s resolved value. When false, error contains the error that was thrown.
Real-world examples
const handleSubmit = async ( formData : FormData ) => {
const result = await toast . promise (
submitForm ( formData ),
{
loading: {
title: 'Submitting form...' ,
description: 'Please wait' ,
},
success: {
title: 'Form submitted!' ,
description: 'Your response has been recorded' ,
},
error : ( err ) => ({
title: 'Submission failed' ,
description: err . message ,
}),
}
);
if ( result . success ) {
navigation . navigate ( 'Success' );
}
};
API request with network error handling
const loadUserProfile = async () => {
const result = await toast . promise (
api . get ( '/user/profile' ),
{
loading: 'Loading profile...' ,
success: 'Profile loaded' ,
error : ( err ) => {
// Customize based on error type
if ( err . message . includes ( 'network' )) {
return {
title: 'No internet connection' ,
description: 'Please check your connection and try again' ,
};
}
if ( err . message . includes ( '401' )) {
return {
title: 'Session expired' ,
description: 'Please sign in again' ,
};
}
return {
title: 'Failed to load profile' ,
description: 'Something went wrong' ,
};
},
}
);
if ( result . success ) {
setProfile ( result . data );
} else if ( result . error ?. message . includes ( '401' )) {
navigation . navigate ( 'Login' );
}
};
File upload with progress
const uploadPhoto = async ( uri : string ) => {
const result = await toast . promise (
uploadToS3 ( uri ),
{
loading: {
title: 'Uploading photo...' ,
description: 'Do not close the app' ,
duration: 120000 , // 2 minutes for large files
},
success: {
title: 'Photo uploaded!' ,
description: 'Your photo is now in your gallery' ,
duration: 3000 ,
},
error : ( err ) => ({
title: 'Upload failed' ,
description: err . message . includes ( 'size' )
? 'Photo is too large. Maximum size is 10MB'
: 'Please try again' ,
duration: 5000 ,
}),
}
);
if ( result . success ) {
refreshGallery ();
}
};
Multiple sequential operations
const processOrder = async ( orderId : string ) => {
// Step 1: Validate
const validationResult = await toast . promise (
validateOrder ( orderId ),
{
loading: 'Validating order...' ,
success: 'Order validated' ,
error: 'Validation failed' ,
}
);
if ( ! validationResult . success ) return ;
// Step 2: Process payment
const paymentResult = await toast . promise (
processPayment ( orderId ),
{
loading: 'Processing payment...' ,
success: 'Payment successful' ,
error : ( err ) => ({
title: 'Payment failed' ,
description: err . message ,
}),
}
);
if ( ! paymentResult . success ) return ;
// Step 3: Fulfill
await toast . promise (
fulfillOrder ( orderId ),
{
loading: 'Fulfilling order...' ,
success: {
title: 'Order complete!' ,
description: 'You will receive a confirmation email' ,
},
error: 'Fulfillment failed' ,
}
);
};
Duration behavior
Loading toasts have a very long default duration (1 hour) to prevent them from auto-dismissing before the promise settles. You can override this if needed.
toast . promise ( quickOperation (), {
loading: {
title: 'Loading...' ,
duration: 5000 , // Auto-dismiss loading state after 5s if promise hasn't settled
},
success: {
title: 'Done!' ,
duration: 3000 , // Default is 4000ms
},
error: 'Failed' , // Uses default 4000ms duration
});
TypeScript support
The promise result is fully typed based on your promise’s return type:
interface User {
id : string ;
name : string ;
}
const result = await toast . promise < User >(
fetchUser ( '123' ),
{
loading: 'Loading user...' ,
success: 'User loaded' ,
error: 'Failed' ,
}
);
if ( result . success ) {
// TypeScript knows result.data is User
console . log ( result . data . name );
}
API reference
toast.promise()
function promise < T >(
promise : Promise < T >,
messages : PromiseMessages
) : Promise < PromiseResult < T >>
Parameters
promise : The promise to track
messages : Configuration object with three states:
loading: Message shown while promise is pending
success: Message shown when promise resolves
error: Message shown when promise rejects (can be a function)
Message types
type MessageInput = string | {
title : string ;
description ?: string ;
duration ?: number ;
}
type ErrorMessageInput = MessageInput | (( error : Error ) => MessageInput )
interface PromiseMessages {
loading : MessageInput ;
success : MessageInput ;
error : ErrorMessageInput ;
}
Return type
interface PromiseResult < T > {
data ?: T ; // Available when success is true
error ?: Error ; // Available when success is false
success : boolean ; // true if resolved, false if rejected
}