Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37117
X-link: https://github.com/facebook/yoga/pull/1265
This deprecates `YGConfigSetUseLegacyStretchBehaviour` and `YGConfigGetUseLegacyStretchBehaviour`and points users to errata APIs instead. Using the C API will fire deprecation warnings, which should create errors in builds with `-Werror`, though they can be ignored if truly needed (like we do with the language bindings which need to expose their own deprecated interface).
Reviewed By: rshest
Differential Revision: D45337198
fbshipit-source-id: 7f069623e38834171f5702382bbf47c37a556a22
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37174
In the future, this will hold TurboModules, as well as legacy/interop modules.
Changelog: [Internal]
Reviewed By: mdvacca
Differential Revision: D45404790
fbshipit-source-id: c0f3d597dfd0edc271f2e89c9ddb26e8a5542367
Summary:
ObjCTurboModule::getArgumentTypeName:
1. Only called from JavaScript.
2. Can raise exceptions.
Thread the jsi::Runtime through this method:
1. So that it can throw jsi::JSErrors.
2. To enfore that it be called from JavaScript.
Changelog: [Internal]
Reviewed By: cipolleschi
Differential Revision: D44887177
fbshipit-source-id: 170399c2919f56d4c15593adf76ec50c061cce69
Summary:
The old and the new native module system perform method argument conversion very differently:
- The TurboModule system converts from JSI Value -> ObjC value. It tries to minimize reliance on RCTConvert.
- The legacy NativeModule system is practically built on top of RCTConvert. It relies on runtime type checking to convert between JSI value -> ObjC value.
So, this diff pulls arg conversion into its own method. That way we can implement argument conversion differently in the TurboModule interop layer.
Changelog: [Internal]
Reviewed By: cipolleschi
Differential Revision: D44850618
fbshipit-source-id: 811d42ed5a78493df9969c546431a4efdf374c0e
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37155
Rationale: The interop TurboModule class will need to use this method to convert return ObjC values to JavaScript values.
Changelog: [Internal]
Reviewed By: cipolleschi
Differential Revision: D44807335
fbshipit-source-id: d44cd1d5effccd8258e034008bd230b299d20451
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37158
This diff sets up a global flag to turn the TurboModule interop on/off.
Changelog: [Internal]
Reviewed By: mdvacca
Differential Revision: D45239212
fbshipit-source-id: ca9f6a24663db84eba2cd483d92c5b51cf2af0c2
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37156
The globals defined using defineReadOnlyGlobal should only ever be defined **at most** once.
So, let's throw an error: in case we accidentally tried to define one of these globals twice (i.e: a mistake I made in D45243456).
NOTE: Redefining the same global twice will throw anyway: you cannot write to a read-only property again. With this diff, the error will be more explicit.
Changelog: [Internal]
Reviewed By: NickGerleman
Differential Revision: D45286774
fbshipit-source-id: aff48ece2984e0fc4340dcbc80ed102ea989ece7
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37157
## Context
NativeAnimatedHelper must be set up in a very particular way:
- On iOS in Bridgeless mode, it must use NativeAnimated**Turbo**Module.
- Everywhere else, it must use NativeAnimatedModule.
## Problem
For some unknown reason, NativeAnimatedModule was getting loaded on D44933587.
## Changes
This diff makes the aformentioned error impossible. It moves the module load gating logic into the two NativeModule spec files.
Changelog: [Internal]
Reviewed By: philIip
Differential Revision: D45292907
fbshipit-source-id: 771bf64d7b491732e8860cf704bc9c3686980e74
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37169
Reduce visibility of methods that should not be public in ReactHost
changelog: [internal] internal
Reviewed By: philIip
Differential Revision: D45378246
fbshipit-source-id: 681c8fc6e4d67b68ac7604f07b9a031d0aa840b0
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37152
Those files are unncessary and can be removed from RNTester.
* Proguard file is empty
* Signing config is unnecessary and we can use the debug one also for release.
Changelog:
[Internal] [Changed] - Remove unnecessary files in RN-Tester
Reviewed By: hoxyq
Differential Revision: D45399388
fbshipit-source-id: fd1c6cccaef668e688a699e31045bdc8103ea98e
Summary:
I accidentally turned off New Architecture on RN-Tester while shipping the Fabric Interop. This reverts it.
Changelog:
[Internal] [Changed] - Re-enable newArch on RN-Tester
Reviewed By: cipolleschi
Differential Revision: D45398914
fbshipit-source-id: 2c36f3d0440f147189de644821e1704c00353bac
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/36967
Changelog: [Internal] - W3CPointerEvents: transform coordinates appropriately for cancel events
This change updates the behavior of pointer cancel events on Android to fire on the correct target. In particular:
1. Transform motion event from child frame into root frame before processing
2. Zero-out coordinates on pointer cancel event in frame of target before dispatching
This is specifically necessary for cancel events due to the way they're propagated between views: we fire a cancel event when a child view starts handling a native gesture (e.g. a scroll view starts being scrolled). However, the native gesture event (MotionEvent) is in the frame of the child view, whereas the rest of the existing pointer event code expects events to be in the frame of the react root view. We don't have to do this conversion for other events since the corresponding MotionEvents are received directly by the root view.
Reviewed By: lunaleaps
Differential Revision: D45064308
fbshipit-source-id: f21d260f6aeb85e5d0efd53a48da6dd1e7b5efbc
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/36959
Changelog: [Internal] - W3CPointerEvents: fix pointercancel test scrollview on Android
On Android the contents of the scrollview were not large enough to allow for scrolling (i.e. they didn't overflow the scroll container). This change sets the height of the content and container explicitly to ensure that the view can be scrolled.
Reviewed By: vincentriemer
Differential Revision: D45064333
fbshipit-source-id: 6aa264d569639bb7d906a3afd887985caa563070
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37122
These are not used anymore.
Changelog: [Internal]
Reviewed By: sammy-SC
Differential Revision: D45314294
fbshipit-source-id: e4b93e0ebc9ed824ed975ad8486f8f0395605275
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37139
This dependency is unnecessary. React Native already exposes a `api` dependency on
`androidx.swiperefreshlayout:swiperefreshlayout` so every consumer will also get it.
This is just another line in the template we can effectively remove.
Changelog:
[Android] [Changed] - Do not explicitely depend on androidx.swiperefreshlayout:swiperefreshlayout
Reviewed By: cipolleschi
Differential Revision: D45390819
fbshipit-source-id: cce34c6a09100d36ee5eb003bb30323f64f0bb9c
Summary:
This diff adds _missing_ README files for all public RN packages.
#### Changes:
For all public RN packages:
- Add _Missing_ READMEs
Update package.json in all RN packages to add:
- Issues, Bugs urls
- Keywords and Homepage urls to respective pkgs
## Changelog:
[GENERAL][ADDED] - Add missing README files for all public RN packages.
[GENERAL][CHANGED] - Update package.json in all RN packages to add required fields.
Pull Request resolved: https://github.com/facebook/react-native/pull/37090
Test Plan: - `yarn lint && yarn flow && yarn test-ci` --> _should be green_
Reviewed By: cortinico
Differential Revision: D45390861
Pulled By: hoxyq
fbshipit-source-id: 524a92de56a7cb553573d9f54ccf40a998dfd35f
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37132
Changelog: [Internal]
The root cause was that one of the custom view managers was returning a read-only map for getExportedCustomDirectEventTypeConstants. React Native merges these maps between view managers, so if the view managers were initialized in a particular order, it will try to merge events into the read-only map and silently crashes.
Reviewed By: rshest
Differential Revision: D45370622
fbshipit-source-id: 7b4b4de372844835d60f81b6700438f56a6b9302
Summary:
`maintainVisibleContentPosition` is broken when using virtualization and the new content pushes visible content outside its "window". This can be reproduced in the example from this diff. When using a large page size it will always push visible content outside of the list "window" which will cause currently visible views to be unmounted so the implementation of `maintainVisibleContentPosition` can't adjust the content inset since the visible views no longer exist.
The first illustration shows the working case, when the new content doesn't push visible content outside the window. The red box represents the window, all views outside the box are not mounted, which means the native implementation of `maintainVisibleContentPosition` has no way to know it exists. In that case the first visible view is https://github.com/facebook/react-native/issues/2, after new content is added https://github.com/facebook/react-native/issues/2 is still inside the window so there's not problem adjusting content offset to maintain position. As you can see Step 1 and 3 result in the same position for all initial views.
The second illustation shows the broken case, when new content is added and pushes the first visible view outside the window. As you can see in step 2 the view https://github.com/facebook/react-native/issues/2 is no longer rendered so there's no way to maintain its position.
#### Illustration 1

#### Illustration 2

To fix `maintainVisibleContentPosition` when using `VirtualizedList` we need to make sure the visible items stay rendered when new items are added at the start of the list.
In order to do that we need to do the following:
- Detect new items that will cause content to be adjusted
- Add cells to render mask so that previously visible cells stay rendered
- Ignore certain updates while scroll metrics are invalid
### Detect new items that will cause content to be adjusted
The goal here is to know that scroll position will be updated natively by the `maintainVisibleContentPosition` implementation. The problem is that the native code uses layout heuristics which are not easily available to JS to do so. In order to approximate the native heuristic we can assume that if new items are added at the start of the list, it will cause `maintainVisibleContentPosition` to be triggered. This simplifies JS logic a lot as we don't have to track visible items. In the worst case if for some reason our JS heuristic is wrong, it will cause extra cells to be rendered until the next scroll event, or content position will not be maintained (what happens all the time currently). I think this is a good compromise between complexity and accuracy.
We need to find how many items have been added before the first one. To do that we save the key of the first item in state `firstItemKey`. When data changes we can find the index of `firstItemKey` in the new data and that will be the amount we need to adjust the window state by.
Note that this means that keys need to be stable, and using index won't work.
### Add cells to render mask so that previously visible cells stay rendered
Once we have the adjusted number we can save this in a new state value `maintainVisibleContentPositionAdjustment` and add the adjusted cells to the render mask.
This state is then cleared when we receive updated scroll metrics, once the native implementation is done adding the new items and adjusting the content offset.
This value is also only set when `maintainVisibleContentPosition` is set so this makes sure this maintains the currently behavior when that prop is not set.
### Ignore certain updates while scroll metrics are invalid
While the `maintainVisibleContentPositionAdjustment` state is set we know that the current scroll metrics are invalid since they will be updated in the native `ScrollView` implementation. In that case we want to prevent certain code from running.
One example is `onStartReached` that will be called incorrectly while we are waiting for updated scroll metrics.
## Changelog
[General] [Fixed] - Fix VirtualizedList with maintainVisibleContentPosition
Pull Request resolved: https://github.com/facebook/react-native/pull/35993
Test Plan:
Added bidirectional paging to RN tester FlatList example. Note that for this to work RN tester need to be run using old architecture on iOS, to use new architecture it requires https://github.com/facebook/react-native/pull/35319
Using debug mode we can see that virtualization is still working properly, and content position is being maintained.
https://user-images.githubusercontent.com/2677334/163294404-e2eeae5b-e079-4dba-8664-ad280c171ae6.mov
Reviewed By: yungsters
Differential Revision: D45294060
Pulled By: NickGerleman
fbshipit-source-id: 8e5228318886aa75da6ae397f74d1801d40295e8
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37093
This replaces product usages of `YGConfigSetUseLegacyStretchBehaviour` with instead setting `YGErrataAll`, to opt out of future conformance fixes which may impact compatibility.
We need to still audit C/C++ usage for where we should be applying `YGErrataClassic`, port this change to the RN desktop fork, then mark the function as deprecated (taking care to allow deprecated functions in the Yoga bindings to call deprecated C ABI functions without warning).
Changelog: [Internal]
Reviewed By: yungsters
Differential Revision: D45300631
fbshipit-source-id: 9f94bdbbe7eda091adac016231083b2486c583d9
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37095
X-link: https://github.com/facebook/yoga/pull/1262
X-link: https://github.com/facebook/litho/pull/942
Now that our own usages are removed, mark this as deprecated to encourage users to move to the errata API. The same will be done to variants of this function on other platforms before releasing, and the functions will be removed after releasing.
Reviewed By: yungsters
Differential Revision: D45300343
fbshipit-source-id: 1ecb2b25021f43a0c97ae6e7976317d28551abea
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37094
This searches fbsource for the following strings corresponding to node or config creation using Yoga Java bindings.
1. `YogaNodeFactory.create`
2. `YogaConfigFactory.create`
Apart from benchmarks/tests, this leaves RN Paper, Litho and Native Templates. These are opted into compatibility with current Yoga behavior, using either `YogaErrata.CLASSIC`, or `YogaErrata.ALL` where `UseLegacyStretchBehaviour` is currently set.
Changelog:
[Internal]
Reviewed By: yungsters
Differential Revision: D45299721
fbshipit-source-id: 74da3dfdb8e5d703feeb44cf73bd18a40e2e936f
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37108
Move the pulling of transactions to the FabricUIManagerBinding, so we have more flexibility in re-using FabricMountingManager for arbitrary MountingTransaction payloads.
Changelog: [Internal]
Reviewed By: genkikondo
Differential Revision: D45312523
fbshipit-source-id: 0aa4edf1ee98bcfc8c7942e9fb8a81ab87842a4c
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37075
X-link: https://github.com/facebook/yoga/pull/1255
This diff wires up YGErrata to a public API, along with existing functions to set UseLegacyStretchBehaviour.
The `UseLegacyStretchBehaviour` functions will be removed after the world internally is transitioned to `YGConfigSetErrata`. This is intentionally breaking, since most users previously enabling `UseLegacyStretchBehaviour` will want to pick a new appropriate errata setting. Internally, users of the API will be moved to`YGErrataAll`.
The overall change looks like:
1. Clean up YGConfig to use accessors/setters
2. Change up YGconfig internal storage
1. Fabric has a config per ShadowNode, so it makes sense to do some size optimization before adding more (free-form bools to bitfield, `std::array<bool,>` to `std::bitset` since not specialized)
3. Wire accessor/setter of UseLegacyStretchBehaviour to errata while both APIs exist
4. Add errata APIs to C ABI
After this we will need to expose the ABI to more language projections, and (more involved), add usages of the API to internal consumption of Yoga before adding more errata and removing `UseLegacyStretchBehaviour`.
Note that this API representation is similar, but distinct to `YGExperimentalFeature`. I think that API may also have made sense as an enum bitset, like we explicitly want for the new API, but it's not really worth changing the existing API to make that happen.
Reviewed By: rshest
Differential Revision: D45254097
fbshipit-source-id: 5c725ce5a77b25c1356f753d11c468587dbd8ded
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37091
X-link: https://github.com/facebook/yoga/pull/1258
This private constructor was added specifically for Fabric when config setting was deprecated, but that is undeprecated now. Fbsource fabric was moved off of it, and the RN desktop for was in the last diff in the stack, so we can remove it now.
Reviewed By: yungsters
Differential Revision: D45292729
fbshipit-source-id: 87b2a1adaafaf817befe44dbc3ac178af59a6e68
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37077
Converts a couple of Yoga config usages in Fabric to public APIs, in preparation for changing the private API.
Changelog: [Internal]
Reviewed By: rshest
Differential Revision: D45254099
fbshipit-source-id: 0d4511fc31b876bfa12f215b72c7c82c940bf342
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37059
This diff introduces InteropEventEmitter, a re-implementation of RCTEventEmitter that works with Fabric and allows to support events on the Fabric Interop for Android.
Thanks to this, users can keep on calling `getJSModule(RCTEventEmitter.class).receiveEvent(...)` in their legacy ViewManagers and they will be using the EventDispatcher
under the hood to dispatch events.
The logic is enabled only if the `unstable_useFabricInterop` flag is turned on. I've turned this on for the template setup and for RN Tester.
On top of this, this diff takes care also of event name "normalization".
On Fabric, all the events needs to be registered with a "top" prefix. With this diff, we'll be adding the "top" prefix at registration time, if the user hasn't added them.
This allows to use legacy ViewManagers on Fabric without having to ask users to change their event name.
Changelog:
[Android] [Added] - Add support for Events on the Fabric Interop Layer
Reviewed By: mdvacca
Differential Revision: D45144246
fbshipit-source-id: 63d4060153907c05977c976379b90574d1f69866
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37088
changelog: [internal]
This is a race condition. parameters need to be copied out, otherwise they might be changed during read.
Reviewed By: luluwu2032
Differential Revision: D45272086
fbshipit-source-id: 9043762dfaaf61d08e187c0d83f743e991a94ed1
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37104
The AppDelegate (and other similar classes) only need to construct the TurboModuleManager for intialization purposes, and should not retain it beyond that. TurboModuleManager retains each of the TurboModule instances and through the new binding mechanism, also JSI pointers, which are invalid beyond the lifetime of the JS context.
Changelog: [iOS] Changed AppDelegate template to avoid retaining TurboModuleManager.
Reviewed By: sammy-SC, cipolleschi
Differential Revision: D45310066
fbshipit-source-id: 4199c9973d832cc07fd32b94f2dcbaa72f4d3920
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/37115
X-link: https://github.com/facebook/yoga/pull/1267
This is an existing bitset enum in the API. Use the facility added in the last diff to add flag operators to it, to avoid the need for casting, and to make it clearer in the generated YGEnums.h that it is a bitset.
Reviewed By: rshest
Differential Revision: D45341504
fbshipit-source-id: 0b80588f3e2e167d4c1c722c6d6608408dd617ba
Summary:
X-link: https://github.com/facebook/yoga/pull/1256
Pull Request resolved: https://github.com/facebook/react-native/pull/37076
This adds a `YGErrata` bitset enum matching the API and guarantees described in https://github.com/facebook/yoga/issues/1247.
It is hooked up in later diffs. There are a couple of `YGExperimentalFeature` values that belong here, but keeping the current options means that the default `YGErrataNone` corresponds to existing default behavior, letting us stage the series of changes as:
1. Implement errata API
2. Update internal Yoga users we want to de-risk to `YGErrataClassic` or `YGErrataAll` (if setting `UseLegacyStretchBehaviour`)
3. Add new errata, changing Yoga defaults to be conformant, while letting internal apps opt into compatibility modes pending experimentation.
I also added a macro to let C++ users of Yoga perform bitwise operations on the enum without casting (already available for C users).
Reviewed By: rshest
Differential Revision: D45254098
fbshipit-source-id: d4b61271a8018f548f2d9d8c953db4b121a502d1
Summary:
X-link: https://github.com/facebook/litho/pull/940
X-link: https://github.com/facebook/yoga/pull/1252
Pull Request resolved: https://github.com/facebook/react-native/pull/36993
Fabric relies on the private C++ internals of Yoga. This creates a conundrum in the open source build due to how header creation in Cocoapods works.
1. The default mechanism of specifying public headers needs to include the private headers for them to be made usable by fabric (by default)
2. Cocoapods will roll up all of the public headers when importing a module
https://github.com/facebook/react-native/pull/33381 fixed the Fabric Cocoapods build which ran into this. React Native relies on FlipperKit which relies on YogaKit, which in turn finally imports the Yoga podspec. Because YogaKit may use Swift, we can only expose the public Yoga C ABI.
The first solution in that PR was to allow RN to access Yoga private headers, but this was changed to instead make all Yoga headers public, and to add ifdefs to all of them to no-op when included outside of a C++ environment.
Talking to Kudo, we should be able to change back to the earlier approach in the PR, to instead expose the private headers to only RN. This lets us avoid exposing headers that we ideally wouldn't be, and lets us avoid the messy ifdefs in every Yoga header.
Changelog: [Internal]
Reviewed By: rshest
Differential Revision: D45139075
fbshipit-source-id: 99152986a578f7aac8324dffe0e18c42a38cc6a5
Summary:
I found a couple scenarios where preloads were issued too aggressively
1. During SSR, if you render a new stylesheet after the preamble flushed
it will flush a preload even if the resource was already preloaded
2. During Client render, if you call `ReactDOM.preload()` it will only
check if a preload exists in the Document before inserting a new one. It
should check for an underlying resource such as a stylesheet link or
script if the preload is for a recognized asset type
DiffTrain build for commit https://github.com/facebook/react/commit/ec5e9c2a75749b0a470b7148738cb85bbb035958.
Reviewed By: kassens
Differential Revision: D45295400
fbshipit-source-id: 6255a2c72d321fdef508d8805b3a5cb807c5c384
Summary:
## Summary
We added some post-processing in the build for RN in #26616 that broke
for users on Windows due to how line endings were handled to the regular
expression to insert some directives in the docblock. This fixes that
problem, reported in #26697 as well.
## How did you test this change?
Verified files are still built correctly on Mac/Linux. Will ask for help
to test on Windows.
DiffTrain build for commit https://github.com/facebook/react/commit/f87e97a0a67fa7cfd7e6f2ec985621c0e825cb23.
Changelog: [Internal]
Reviewed By: kassens
Differential Revision: D45279164
Pulled By: rubennorte
fbshipit-source-id: 5372e8357c99bb09704715b155cb85422ec7886a
Summary:
useMemoCache wasn't previously supported in the DevTools, so any attempt
to inspect a component using the hook would result in a
`dispatcher.useMemoCache is not a function (it is undefined)` error.
DiffTrain build for commit https://github.com/facebook/react/commit/25b99efe0c9c9d593c86829386c86740d409fa8c.
Changelog: [Internal]
Reviewed By: kassens
Differential Revision: D45278799
Pulled By: poteto
fbshipit-source-id: 613b28f9793574cef6fed04211f1fc2d0e600119
Summary:
Adds changelog for new patch.
## Changelog:
<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->
[Internal] [Changed] - add changelog entry for 0.68.7
Pull Request resolved: https://github.com/facebook/react-native/pull/37106
Test Plan: N/A
Reviewed By: dmytrorykun
Differential Revision: D45313093
Pulled By: cipolleschi
fbshipit-source-id: d84e8d61626181b2ebfad9304c5c9be4b0123015
Summary:
This is enabled in the canary channels, but because it's relatively
untested, we'll disable it at Meta until they're ready to start trying
it out. It can change some behavior even if you don't intentionally
start using the API.
The reason it's not a dynamic flag is that it affects the external Fizz
runtime, which currently can't read flags at runtime.
DiffTrain build for commit https://github.com/facebook/react/commit/ed545ae3d3478cd82aa498494025cb3a15188e4c.
Changelog: [Internal]
Reviewed By: poteto
Differential Revision: D45278076
Pulled By: kassens
fbshipit-source-id: e9d56912b339384990edd31c4eba5f784fcef932
Summary:
We used to have Event Replaying for any kind of Discrete event where
we'd track any event after hydrateRoot and before the async code/data
has loaded in to hydrate the target. However, this didn't really work
out because code inside event handlers are expected to be able to
synchronously read the state of the world at the time they're invoked.
If we replay discrete events later, the mutable state around them like
selection or form state etc. may have changed.
This limitation doesn't apply to Client Actions:
- They're expected to be async functions that themselves work
asynchronously. They're conceptually also in the "navigation" events
that happen after the "submit" events so they're already not
synchronously even before the first `await`.
- They're expected to operate mostly on the FormData as input which we
can snapshot at the time of the event.
This PR adds a bit of inline script to the Fizz runtime (or external
runtime) to track any early submit events on the page - but only if the
action URL is our placeholder `javascript:` URL. We track a queue of
these on `document.$$reactFormReplay`. Then we replay them in order as
they get hydrated and we get a handle on the Client Action function.
I add the runtime to the `bootstrapScripts` phase in Fizz which is
really technically a little too late, because on a large page, it might
take a while to get to that script even if you have displayed the form.
However, that's also true for external runtime. So there's a very short
window we might miss an event but it's good enough and better than
risking blocking display on this script.
The main thing that makes the replaying difficult to reason about is
that we can have multiple instance of React using this same queue. This
would be very usual but you could have two different Reacts SSR:ing
different parts of the tree and using around the same version. We don't
have any coordinating ids for this. We could stash something on the form
perhaps but given our current structure it's more difficult to get to
the form instance in the commit phase and a naive solution wouldn't
preserve ordering between forms.
This solution isn't 100% guaranteed to preserve ordering between
different React instances neither but should be in order within one
instance which is the common case.
The hard part is that we don't know what instance something will belong
to until it hydrates. So to solve that I keep everything in the original
queue while we wait, so that ordering is preserved until we know which
instance it'll go into. I ended up doing a bunch of clever tricks to
make this work. These could use a lot more tests than I have right now.
Another thing that's tricky is that you can update the action before
it's replayed but we actually want to invoke the old action if that
happens. So we have to extract it even if we can't invoke it right now
just so we get the one that was there during hydration.
DiffTrain build for commit https://github.com/facebook/react/commit/bf449ee74e5e98af3d08c87bb6a9f22a021f3522.
Changelog: [Internal]
Reviewed By: poteto
Differential Revision: D45274088
Pulled By: kassens
fbshipit-source-id: 7e9d96731f0bc72ea5fa3ffc6ce3f4a1dfe80d90