Smart spinner If action is less than 200 ms spinner may look as unnecessary flicker Spinner should not be shown immediately Once shown, keep it visible for a minimum duration 500 ms import { asyncDelay } from '@shared/utils/delay' const MIN_SPINNER_TIME = 400 const SPINNER_DELAY = 200 const sayHelloAfterDelay = async (): Promise<'Hello'> => { await asyncDelay(300) return 'Hello' } const checkWetherToShowSpinnerOrNot = async (): Promise<'show spinner'> => { await asyncDelay(SPINNER_DELAY) return 'show spinner' } const onClick = async (): Promise<void> => { const res = await Promise.race([ checkWetherToShowSpinnerOrNot(), sayHelloAfterDelay(), ]) if (res !== 'show spinner') { console.log('✅ Fast response, no spinner') console.log(res) return } if (res === 'show spinner') { console.log('⏳ Show spinner') const spinnerStart = Date.now() const finalRes = await sayHelloAfterDelay() const spinnerTime = Date.now() - spinnerStart const remaining = MIN_SPINNER_TIME - spinnerTime if (remaining > 0) { console.log('⏳ Extend spinner a bit') await asyncDelay(remaining) // ensure spinner is visible for min time } console.log('✅ Done:', finalRes) } } export const TestPage = (): React.JSX.Element => { return ( <button onClick={onClick} type='button' > Click me </button> ) }