When an async dependency (cloud restore, sidecar/Hub transport, source-control action) can fail or be retried, design UI and side effects so the app remains in a safe, recoverable state:
Example pattern (success-gated state + recoverable fallback):
const [loaded, setLoaded] = useState(false);
const hubFailed = transport === 'connected' && hub.state === 'failed';
// Only “commit” UI state when action succeeds
async function onCommit() {
const ok = await onAction({ type: 'commit', message });
if (!ok) return; // keep message + UI unchanged
setMessage('');
}
// Failure-mode: replace app with fallback screen
return (
<>
{loaded && !hubFailed ? <App /> : null}
{(!loaded || hubFailed) ? <HubStartupScreen /> : null}
</>
);
Apply this as a standard for any feature that depends on external services: define the “safe state” on failure, ensure transitions/cleanup are success-gated, and wire retries to the most reliable recovery signal (typically reconnect).