React Forum
Blog & Guide Responses
Sep 03, 2022 · 04:00 AM

Escape Hatches - discussion (2022-09-03)

Started by Talia Moss
externalreact.devescape hatchesrefslayout effectsimperative

We just did a refactor where we removed a bunch of imperative code and now I'm curious: what escape hatches do you allow by default, and how do you keep them from spreading?

Read the article

When do you decide an escape hatch is just DOM integration vs a sign the UI contract needs restructuring? Do you wrap escape hatches in named helpers so they are auditable? Do you render a small signal for hatch-driven behavior so it is testable and reproducible?

Comments (10)

Back to latest
Mina Calder
Sep 03, 2022 · 04:06 AM

Focus and measurement, sure. Anything that changes navigation or data posture should be a contract key, not a ref trick.

Dmitri Kline
Sep 03, 2022 · 04:14 AM

We allow a small set of hatches, but we require: named helper + a rendered signal when behavior changes.

Related: Accessibility Best Practices and Routing and Navigation.

Salma Qureshi
Sep 03, 2022 · 04:22 AM

Wrapping hatches was the big win for us:

tsx
function useScrollToTopOnNav(enabled: boolean) {
  useLayoutEffect(() => {
    if (!enabled) return;
    window.scrollTo({ top: 0, behavior: 'instant' as ScrollBehavior });
  }, [enabled]);
}

We make it observable by rendering a tiny marker in the shell when the hatch is enabled (e.g. data-escape='scrollToTop').

Keira Santos
Sep 03, 2022 · 04:31 AM

Counterpoint: not every hatch deserves a signal.

We only render signals when the hatch affects user-visible behavior that support needs to reason about.

Talia Moss
Sep 03, 2022 · 04:36 AM

That feels reasonable. The bug that triggered this was focus-related and support couldn't reproduce it reliably.

So for us, focus might be one of the hatch categories where signals are worth it.

Keira Santos
Sep 03, 2022 · 04:39 AM

Yeah. Focus is one of the few small-but-crucial behaviors that benefits from being test-visible.

Theo Bennett
Sep 03, 2022 · 04:44 AM

I delete hatches that exist to settle state. If you need to settle state, you probably need derived evidence or a different boundary.

Hana Saito
Sep 03, 2022 · 04:52 AM

We keep an escape hatch inventory by searching for the helper names. That way hatches don't hide as random one-off effects.

Amina Farouk
Sep 03, 2022 · 05:03 AM

We had a performance problem caused by measuring layout on every render. Once we made measurement an explicit hatch with a signal, it was obvious where it was happening and we could throttle it.

tsx
function useMeasureHatch(enabled: boolean, ref: any) {
  useLayoutEffect(() => {
    if (!enabled) return;
    if (!ref.current) return;
    const rect = ref.current.getBoundingClientRect();
    // store the evidence once so it doesn't re-measure forever
  }, [enabled]);
}

return <div data-escape="measure" data-enabled={String(enabled)} />;
Jules Kwon
Sep 03, 2022 · 05:15 AM

Escape hatches are fine. Invisible escape hatches are not.

Inez Park
Sep 03, 2022 · 05:27 AM

The biggest issue with hatches is they become tribal knowledge. Naming + signals turns them into something you can reason about.

Benji Rios
Sep 03, 2022 · 05:41 AM

If you can't explain the hatch from a screenshot, you probably shouldn't ship it.