-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
An effect that inserts iframes may run twice in Safari #2814
Comments
I can reproduce that in the latest Safari. It seems like it does something different when scheduling import { options } from "preact";
// Resolves duplicate effect calls in Safari
options.requestAnimationFrame = Promise.prototype.then.bind(Promise.resolve()); |
Another option would be to use a double promise resolution for the render queue. |
@developit I was able to resolve this issue in Safari with the following option override: import {options} from 'preact';
options.requestAnimationFrame = Promise.prototype.then.bind(Promise.resolve().then(() => Promise.resolve())); Is this what you were suggesting (a double promise resolution)? I assume so but want to make sure I'm not missing something. Would this be something Preact would accept as a contribution? It's a bit of an unusual one since this mechanism is presumably a bit more expensive than the current I also noticed this pattern is internally used to create a function for deferring updates ( Line 181 in c7f57db
(Sorry for reviving a zombie issue a year after our last comment, at Shopify we got bit by this issue again :P) |
Did anyone file a WebKit bug for this? We're seeing the same issue in facebook/react#22459. |
Awesome, thanks for filing that @gaearon! I added a comment over on the trac bug with some bounds around what cases trigger flushing. |
Should be fixed in WebKit/WebKit#1909 |
Despite being fixed in Webkit - this issue is still present on Safari <16 which is a huge number of users still. On the React side, they were able to ship a workaround so that users of the library don't need to implement workarounds, should something similar be considered for preact? See: |
Reproduction
Here's a codesandbox showing a Preact effect running twice in Safari: https://codesandbox.io/s/safari-duplicate-effects-b2lnf.
The root cause appears to be Safari running pending promises when an iframe is inserted into the DOM. You can verify by running this code in Safari's dev console:
As far as I can tell, the exact setup to reproduce is:
The state update enqueues components for re-render, then the iframe insertion causes Safari to immediately kick off a re-render inside Preact's current render loop. This happens before the current render has cleared effects arrays, so the effects are executed again.
The sandbox looks contrived, but I ran into this while integrating PayPal into a Preact app.
Steps to reproduce
Running the sandbox in Safari 13.1.2 should illustrate the problem. The same sandbox will show one less element in Chrome.
Expected Behavior
Preact should not run an effect with no dependencies twice.
Actual Behavior
Preact runs an effect with no dependencies twice.
The text was updated successfully, but these errors were encountered: