question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

React 18 StrictMode

See original GitHub issue

Hey! I’m having an issue opening my custom modal with FocusTrap in StrictMode after upgrading to React 18. When the modal state is opened onDeactive is called immediately (probably because of the double render in Strictmode), which closes the dialog. I see you have recently released a fix for StrictMode but it doesn’t fix this issue.

I made a demo where i just copied the example from: demo/js/demo-special-element.js

The change i made in the demo is to only render the FocusTrap element when it is active.

Code sandbox demo: https://codesandbox.io/s/0vhfsb

Is this a bug or should i implement it differently?

Issue Analytics

  • State:closed
  • Created a year ago
  • Reactions:1
  • Comments:7 (7 by maintainers)

github_iconTop GitHub Comments

2reactions
stefcameroncommented, Jul 2, 2022

@lasseklovstad I had a closer look. Turns out, AFAICT, the trap is doing what it’s supposed to do, especially after #721, which is to handle being immediately unmounted and remounted after being initially mounted (behavior caused by Strict Mode).

This works for the use case in #721 when you don’t have a component outside the <FocusTrap> that is controlling the trap’s active state. A trap is active by default, so if you just plop one down and render, under Strict Mode, the fix in #721 is employed to restore the trap to an active state in the remount.

But in your case, because you have this activeTrap state variable, and you have this method tied to the trap’s onPostDeactivate event:

  unmountTrap() {
    this.setState({ activeTrap: false });
  }

thing don’t work so well because, under Strict Mode, the trap gets unmounted – which causes this handler to get called, thus setting activeTrap to false. Then the trap is remounted, but then there’s an immediate React state update (because the outer component’s activeTrap state changed from true to false), and since you’re conditionally rendering the trap when activeTrap is true, the trap gets unmounted again, the handler gets called again (has no effect this time since the state is already false), and things settle.

And you’re left with no visible trap.

So this isn’t a bug with the trap. Of course, not using Strict Mode, it works just right. The trap renders when activeTrap becomes true, and it’s active.

I’m not sure what to suggest here. As you know, I’m not a fan of this behavior of Strict Mode. There are other things Strict Mode which I’m fine with. But this unmount/remount thing, no. IMO, React has an idea of what they want to do in the future (i.e. temporarily/dynamically disabling parts of the UI by unmounting them, and then reactivate them later by remounting them), but this behavior violates their API (as I explained in #720). And focus trap is behaving correctly according to the API. 🤷‍♂️ Not sure how to reconcile that, short of being able to somehow detect strict mode, and have the trap behave differently in that case (i.e. by expecting an initial unmount and setting a flag to remember it has happened, and not deactivating the trap, avoiding triggering the deactivation event handlers, that one time), something I’m also not a fan of.

1reaction
stefcameroncommented, Sep 2, 2022

@Slapbox

I think the issue really for us is that onDeactivate fires. Is there any way it could be prevented in Strict Mode?

I don’t know of any way to detect strict mode, and I’m guessing that would be beside the point of strict mode. I also don’t think it’s good to have a version of the component that works in strict mode one way, and another version that works in not strict mode another way… I really loathe strict mode for this.

We used onDeactivate to replace react-onClickOutside - which we previously used together with focus-trap-react, but 10.0.0 made that impossible (https://github.com/focus-trap/focus-trap-react/issues/719)

What in 10 made this impossible? The only thing that changed in 10 was the tabbable dependency, and there’s a workaround to restore the old behavior. There were no code changes in 10 at all. Functionally, aside from the need for the workaround for old behavior (if it’s even an issue), the library is the same as it was in 9.0.2

Read more comments on GitHub >

github_iconTop Results From Across the Web

Strict Mode
StrictMode is a tool for highlighting potential problems in an application. Like Fragment , StrictMode does not render any visible UI. It activates...
Read more >
Using strict mode in React 18: A guide to its new behaviors
React v18 introduced new strict mode behavior regarding unmounting and remounting. Now, each element will be unmounted and remounted with the ...
Read more >
How to use React Strict Mode in React 18
React Strict Mode is a developer tool highlighting potential bugs or issues in a React application's codebase. It provides warnings to ...
Read more >
Does strict mode work differently with React 18?
In React 18, StrictMode gets an additional behavior to ensure it's compatible with reusable state. When Strict Mode is enabled, React ...
Read more >
React
If your app doesn't work after upgrading to React 18, the first thing to check is whether it's wrapped in <StrictMode>. Strict Mode...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found