Skip to the content

React event handlers

Start a context in a React event handler, and keep it in the async code of the handler.

Start the context in the handler

React dispatches the events of all components from one listener on the root element. React added that listener when the application started, in the root context. Thus, a React handler starts in the root context. Start the context of the operation in the handler:

function SaveButton({ draft } : { draft : Draft }) {
    const onClick = () => traced("save", async () => {
        await api("/api/documents", { method : "POST", body : JSON.stringify(draft) });
        toast("Saved");
    });
    return <button onClick={onClick}>Save</button>;
}

Each await in the function of traced() keeps the trace. The then callbacks and the timers that the function starts also keep it.

Effects

An effect starts in the root context. Start a context in the effect if its async code needs one:

useEffect(() => {
    let active = true;
    void traced("load profile", async () => {
        const profile = await api<Profile>(`/api/profiles/${userId}`);
        if (active) setProfile(profile);
    });
    return () => { active = false; };
}, [userId]);

Configure the build

Add the Vite plugin, or the Babel preset, to the build of the application. The plugin also transforms the async code of the dependencies. React itself contains no async code that a handler waits for.

async-browser-context: AsyncLocalStorage and the TC39 AsyncContext API for browsers. The source code is on GitHub.

To change a page, edit its file in site/content/. The writing style guide tells you how.

An AI model (Claude, from Anthropic) wrote most of the text and the code of this site and of the library, under the direction of the author. The tests and the STE linter examine them.