The final state of the React Conf 2025 Async React talk.
View the app: https://async-react.dev/
Install:
yarn
Run the frontend:
yarn dev
Optional: you can use a real backend by updating .env
to:
VITE_USE_REAL_SERVER=true
And run the backend:
yarn server
This is useful when viewing React Performance Tracks because you can see the real network requests.
This repo shows the future vision for how product code will be written in React without needing additional APIs.
This is possible, but implementing Async React features in:
- Routing: The router uses transitions by default, so users don't need to wrap navigation updates in additional transitions.
- Data Fetching: The data fetching layer uses suspense by default, so users can use transitions and suspense throughout their app.
- Design Components: The design components expose
action
props so callbacks are in async transitions by default. To provide user feedback, these components also use optimistic updates to automatically show results and delayed loading states, no matter what the product code does in the action.
In the app, there is a network debugger at the bottom. By changing the timing for events, you can see the experience for:
- Fast network (<150ms): No loading states, the app performs and feels synchronous.
- Slow network (>150ms): Automatically displays loading states, and batches updates to prevent async bugs.
Our code for the login form is simple and declarative:
export default function Login() {
const router = useRouter();
const [fields, setFields] = useState(initialFieldData);
async function submitAction() {
await login(fields.username, fields.password);
await prefetchLessons();
router.navigate("/");
}
return (
<Design.LoginForm fields={fields} setFields={setFields}>
<Design.Button action={submitAction}>Login</Design.Button>
</Design.LoginForm>
);
}
When network is fast, login will instantly navigate to the logged in page, with no visible loading states:
async-react-login-sync.mov
When network is slow, but under a second, the prefetching allows us to still animate in the logged in page without a glimmer:
async-react-login-async-fast.mov
When network is over 1s, we animate to fallbacks while the data loads:
async-react-login-async-slow.mov
Our code for the home page is also simple and declarative:
export default function Home() {
const router = useRouter();
const search = router.search.q || "";
const tab = router.search.tab || "all";
function searchAction(value) {
router.setParams("q", value);
}
function tabAction(value) {
router.setParams("tab", value);
}
async function completeAction(id) {
await data.mutateToggle(id);
router.refresh();
}
return (
<>
<Design.SearchInput value={search} changeAction={searchAction} />
<Design.TabList activeTab={tab} changeAction={tabAction}>
<Suspense fallback={<Design.FallbackList />}>
<LessonList
tab={tab}
search={search}
completeAction={completeAction}
/>
</Suspense>
</Design.TabList>
</>
);
}
When network is fast, the app feels like it's synchronous:
async-react-flow-sync.mov
As network slows, the app will automatically show loading states:
async-react-flow-async.mov
At React Conf 2025, we announced a new working group to make Async React the default for React apps.
Check out the Async React Working Group to follow the progress.