**This API is not intended to ship. This is a temporary unstable hook
for internal performance profiling.**
This PR exposes `unstable_useContextWithBailout`, which takes a compare
function in addition to Context. The comparison function is run to
determine if Context propagation and render should bail out earlier.
`unstable_useContextWithBailout` returns the full Context value, same as
`useContext`.
We can profile this API against `useContext` to better measure the cost
of Context value updates and gather more data around propagation and
render performance.
The bailout logic and test cases are based on
https://github.com/facebook/react/pull/20646
Additionally, this implementation allows multiple values to be compared
in one hook by returning a tuple to avoid requiring additional Context
consumer hooks.
Following https://github.com/facebook/react/pull/30436
Concurrent by default strategy has been unshipped. Here we clean up the
`allowConcurrentByDefault` path and related logic/tests.
For now, this keeps the `concurrentUpdatesByDefaultOverride` argument in
`createContainer` and `createHydrationContainer` and ignores the value
to prevent more breaking changes to `react-reconciler` in the RC stage.
Concurrent by default has been unshipped! Let's clean it up.
Here we remove `forceConcurrentByDefaultForTesting`, which allows us to
run tests against both concurrent strategies. In the next PR, we'll
remove the actual concurrent by default code path.
While the goal is to remove legacy context completely, I think we can
already land the removal of legacy context for function components. I
didn't even know this feature existed until reading the code recently.
The win is just a couple of property lookups on function renders, but it
trims down the API already as the full removal will likely still take a
bit more time.
www: Starting with enabled test renderer and a feature flag for
production rollout.
RN: Not enabled, will follow up on this.
Object literals should be faster at least on React Native with Hermes as
the JS engine.
It might also be interesting to confirm the old comments in this file
from years ago are even still valid. Creating an object from a literal
should be a simpler operation.
It's a bit unfortunate that this introduces a bunch of copied code, but
since we rearely update the fields on fibers, this seems like an okay
tradeoff for a hot code path. An alternative would be some sort of macro
system, but that doesn't seem worth the extra complexity.
## Summary
We currently do deep diffing for object props, and also use custom
differs, if they are defined, for props with custom attribute config.
The idea is to simply do a `===` comparison instead of all that work. We
will do less computation on the JS side, but send more data to native.
The hypothesis is that this change should be neutral in terms of
performance. If that's the case, we'll be able to get rid of custom
differs, and be one step closer to deleting view configs.
This PR adds the `enableShallowPropDiffing` feature flag to support this
experiment.
## How did you test this change?
With `enableShallowPropDiffing` hardcoded to `true`:
```
yarn test packages/react-native-renderer
```
This fails on the following test cases:
- should use the diff attribute
- should do deep diffs of Objects by default
- should skip deeply-nested changed functions
Which makes sense with this change. These test cases should be deleted
if the experiment is shipped.
`disableDOMTestUtils` and the FB build `ReactTestUtilsFB` allowed us to
finish migrating internal callsites off of ReactTestUtils. Now that
usage is cleaned up, we can remove the flag, build artifact, and test
coverage for the deprecated utility methods.
## Summary
The experiment has shown no significant performance changes. This PR
removes it.
## How did you test this change?
```
yarn flow native
yarn lint
```
This is the first step to experimenting with a new type of stack traces
behind the `enableOwnerStacks` flag - in DEV only.
The idea is to generate stacks that are more like if the JSX was a
direct call even though it's actually a lazy call. Not only can you see
which exact JSX call line number generated the erroring component but if
that's inside an abstraction function, which function called that
function and if it's a component, which component generated that
component. For this to make sense it really need to be the "owner" stack
rather than the parent stack like we do for other component stacks. On
one hand it has more precise information but on the other hand it also
loses context. For most types of problems the owner stack is the most
useful though since it tells you which component rendered this
component.
The problem with the platform in its current state is that there's two
ways to deal with stacks:
1) `new Error().stack`
2) `console.createTask()`
The nice thing about `new Error().stack` is that we can extract the
frames and piece them together in whatever way we want. That is great
for constructing custom UIs like error dialogs. Unfortunately, we can't
take custom stacks and set them in the native UIs like Chrome DevTools.
The nice thing about `console.createTask()` is that the resulting stacks
are natively integrated into the Chrome DevTools in the console and the
breakpoint debugger. They also automatically follow source mapping and
ignoreLists. The downside is that there's no way to extract the async
stack outside the native UI itself so this information cannot be used
for custom UIs like errors dialogs. It also means we can't collect this
on the server and then pass it to the client for server components.
The solution here is that we use both techniques and collect both an
`Error` object and a `Task` object for every JSX call.
The main concern about this approach is the performance so that's the
main thing to test. It's certainly too slow for production but it might
also be too slow even for DEV.
This first PR doesn't actually use the stacks yet. It just collects them
as the first step. The next step is to start utilizing this information
in error printing etc.
For RSC we pass the stack along across over the wire. This can be
concatenated on the client following the owner path to create an owner
stack leading back into the server. We'll later use this information to
restore fake frames on the client for native integration. Since this
information quickly gets pretty heavy if we include all frames, we strip
out the top frame. We also strip out everything below the functions that
call into user space in the Flight runtime. To do this we need to figure
out the frames that represents calling out into user space. The
resulting stack is typically just the one frame inside the owner
component's JSX callsite. I also eagerly strip out things we expect to
be ignoreList:ed anyway - such as `node_modules` and Node.js internals.
Following #28768, add a path to testing Fast JSX on www.
We want to measure the impact of Fast JSX and enable a path to testing
before string refs are completely removed in www (which is a work in
progress).
Without `disableStringRefs`, we need to copy any object with a `ref` key
so we can pass it through `coerceStringRef()` and copy it into the
object. This de-opt path is what is gated behind
`enableFastJSXWithStringRefs`.
The additional checks should have no perf impact in OSS as the flags
remain true there and the build output is not changed. For www, I've
benchmarked the addition of the boolean checks with values cached at
module scope. There is no significant change observed from our
benchmarks and any latency will apply to test and control branches
evenly. This added experiment complexity is temporary. We should be able
to clean it up, along with the flag checks for `enableRefAsProp` and
`disableStringRefs` shortly.
## Summary
This PR introduces a faster version of the `addProperties` function.
This new function is basically the `diffProperties` with `prevProps` set
to `null`, propagated constants, and all the unreachable code paths
collapsed.
## How did you test this change?
I've tested this change with [the benchmark
app](https://github.com/react-native-community/RNNewArchitectureApp/tree/new-architecture-benchmarks)
and got ~4.4% improvement in the view creation time.
This removes the automatic patching of the global `fetch` function in
Server Components environments to dedupe requests using `React.cache`, a
behavior that some RSC framework maintainers have objected to.
We may revisit this decision in the future, but for now it's not worth
the controversy.
Frameworks that have already shipped this behavior, like Next.js, can
reimplement it in userspace.
I considered keeping the implementation in the codebase and disabling it
by setting `enableFetchInstrumentation` to `false` everywhere, but since
that also disables the tests, it doesn't seem worth it because without
test coverage the behavior is likely to drift regardless. We can just
revert this PR later if desired.
Stacked on #28849, #28854, #28853. Behind a flag.
If you're following along from the side-lines. This is probably not what
you think it is.
It's NOT a way to get updates to a component over time. The
AsyncIterable works like an Iterable already works in React which is how
an Array works. I.e. it's a list of children - not the value of a child
over time.
It also doesn't actually render one component at a time. The way it
works is more like awaiting the entire list to become an array and then
it shows up. Before that it suspends the parent.
To actually get these to display one at a time, you have to opt-in with
`<SuspenseList>` to describe how they should appear. That's really the
interesting part and that not implemented yet.
Additionally, since these are effectively Async Functions and uncached
promises, they're not actually fully "supported" on the client yet for
the same reason rendering plain Promises and Async Functions aren't.
They warn. It's only really useful when paired with RSC that produces
instrumented versions of these. Ideally we'd published instrumented
helpers to help with map/filter style operations that yield new
instrumented AsyncIterables.
The way the implementation works basically just relies on unwrapThenable
and otherwise works like a plain Iterator.
There is one quirk with these that are different than just promises. We
ask for a new iterator each time we rerender. This means that upon retry
we kick off another iteration which itself might kick off new requests
that block iterating further. To solve this and make it actually
efficient enough to use on the client we'd need to stash something like
a buffer of the previous iteration and maybe iterator on the iterable so
that we can continue where we left off or synchronously iterate if we've
seen it before. Similar to our `.value` convention on Promises.
In Fizz, I had to do a special case because when we render an iterator
child we don't actually rerender the parent again like we do in Fiber.
However, it's more efficient to just continue on where we left off by
reusing the entries from the thenable state from before in that case.
We have changed the shape (and the runtime) of React Elements. To help
avoid precompiled or inlined JSX having subtle breakages or deopting
hidden classes, I renamed the symbol so that we can early error if
private implementation details are used or mismatching versions are
used.
Why "transitional"? Well, because this is not the last time we'll change
the shape. This is just a stepping stone to removing the `ref` field on
the elements in the next version so we'll likely have to do it again.
Adds an experimental feature flag to the implementation of useMemoCache,
the internal cache used by the React Compiler (Forget).
When enabled, instead of treating the cache as copy-on-write, like we do
with fibers, we share the same cache instance across all render
attempts, even if the component is interrupted before it commits.
If an update is interrupted, either because it suspended or because of
another update, we can reuse the memoized computations from the previous
attempt. We can do this because the React Compiler performs atomic
writes to the memo cache, i.e. it will not record the inputs to a
memoization without also recording its output.
This gives us a form of "resuming" within components and hooks.
This only works when updating a component that already mounted. It has
no impact during initial render, because the memo cache is stored on the
fiber, and since we have not implemented resuming for fibers, it's
always a fresh memo cache, anyway.
However, this alone is pretty useful — it happens whenever you update
the UI with fresh data after a mutation/action, which is extremely
common in a Suspense-driven (e.g. RSC or Relay) app.
So the impact of this feature is faster data mutations/actions (when the
React Compiler is used).
## Summary
This PR adds early return to the `diff` function. We don't need to go
through all the entries of `nextProps`, process and deep-diff the values
if `nextProps` is the same object as `prevProps`. Roughly 6% of all
`diffProperties` calls can be skipped.
## How did you test this change?
RNTester.
This adds support in Flight for serializing four kinds of streams:
- `ReadableStream` with objects as a model. This is a single shot
iterator so you can read it only once. It can contain any value
including Server Components. Chunks are encoded as is so if you send in
10 typed arrays, you get the same typed arrays out on the other side.
- Binary `ReadableStream` with `type: 'bytes'` option. This supports the
BYOB protocol. In this mode, the receiving side just gets `Uint8Array`s
and they can be split across any single byte boundary into arbitrary
chunks.
- `AsyncIterable` where the `AsyncIterator` function is different than
the `AsyncIterable` itself. In this case we assume that this might be a
multi-shot iterable and so we buffer its value and you can iterate it
multiple times on the other side. We support the `return` value as a
value in the single completion slot, but you can't pass values in
`next()`. If you want single-shot, return the AsyncIterator instead.
- `AsyncIterator`. These gets serialized as a single-shot as it's just
an iterator.
`AsyncIterable`/`AsyncIterator` yield Promises that are instrumented
with our `.status`/`.value` convention so that they can be synchronously
looped over if available. They are also lazily parsed upon read.
We can't do this with `ReadableStream` because we use the native
implementation of `ReadableStream` which owns the promises.
The format is a leading row that indicates which type of stream it is.
Then a new row with the same ID is emitted for every chunk. Followed by
either an error or close row.
`AsyncIterable`s can also be returned as children of Server Components
and then they're conceptually the same as fragment arrays/iterables.
They can't actually be used as children in Fizz/Fiber but there's a
separate plan for that. Only `AsyncIterable` not `AsyncIterator` will be
valid as children - just like sync `Iterable` is already supported but
single-shot `Iterator` is not. Notably, neither of these streams
represent updates over time to a value. They represent multiple values
in a list.
When the server stream is aborted we also close the underlying stream.
However, closing a stream on the client, doesn't close the underlying
stream.
A couple of possible follow ups I'm not planning on doing right now:
- [ ] Free memory by releasing the buffer if an Iterator has been
exhausted. Single shots could be optimized further to release individual
items as you go.
- [ ] We could clean up the underlying stream if the only pending data
that's still flowing is from streams and all the streams have cleaned
up. It's not very reliable though. It's better to do cancellation for
the whole stream - e.g. at the framework level.
- [ ] Implement smarter Binary Stream chunk handling. Currently we wait
until we've received a whole row for binary chunks and copy them into
consecutive memory. We need this to preserve semantics when passing
typed arrays. However, for binary streams we don't need that. We can
just send whatever pieces we have so far.
Per team discussion, this upgrades the `initialValue` argument for
`useDeferredValue` from experimental to canary.
- Original implementation PR:
https://github.com/facebook/react/pull/27500
- API documentation PR: https://github.com/reactjs/react.dev/pull/6747
I left it disabled at Meta for now in case there's old code somewhere
that is still passing an `options` object as the second argument.
This removes defaultProps support for all component types except for
classes. We've chosen to continue supporting defaultProps for classes
because lots of older code relies on it, and unlike function components,
(which can use default params), there's no straightforward alternative.
By implication, it also removes support for setting defaultProps on
`React.lazy` wrapper. So this will not work:
```js
const MyClassComponent = React.lazy(() => import('./MyClassComponent'));
// MyClassComponent is not actually a class; it's a lazy wrapper. So
// defaultProps does not work.
MyClassComponent.defaultProps = { foo: 'bar' };
```
However, if you set the default props on the class itself, then it's
fine.
For classes, this change also moves where defaultProps are resolved.
Previously, defaultProps were resolved by the JSX runtime. This change
is only observable if you introspect a JSX element, which is relatively
rare but does happen.
In other words, previously `<ClassWithDefaultProp />.props.aDefaultProp`
would resolve to the default prop value, but now it does not.
Cleanup enableUseRefAccessWarning flag
I don't think this flag has a path forward in the current
implementation. The detection by stack trace is too brittle to detect
the lazy initialization pattern reliably (see e.g. some internal tests
that expect the warning because they use lazy intialization, but a
slightly different pattern then the expected pattern.
I think a new version of this could be to fully ban ref access during
render with an alternative API for the exceptional cases that today
require ref access during render.
Only the FB entry point has legacy mode now so we can move the remaining
code in there.
Also enable disableLegacyMode in modern www builds since it doesn't
expose those entry points.
Now dependent on #28709.
---------
Co-authored-by: Josh Story <story@hey.com>
We've rolled out this flag internally on WWW. This PR removed flag
`enableCustomElementPropertySupport`
Test plan:
-- `yarn test`
Co-authored-by: Ricky Hanlon <rickhanlonii@gmail.com>
Remove module pattern function component support (flag only)
> This is a redo of #27742, but only including the flag removal,
excluding further simplifications.
The module pattern
```
function MyComponent() {
return {
render() {
return this.state.foo
}
}
}
```
has been deprecated for approximately 5 years now. This PR removes
support for this pattern.
This breaks internal tests, so must be something in the refactor. Since
it's the top commit let's revert and split into two PRs, one that
removes the flag and one that does the refactor, so we can find the bug.
The module pattern
```
function MyComponent() {
return {
render() {
return this.state.foo
}
}
}
```
has been deprecated for approximately 5 years now. This PR removes
support for this pattern. It also simplifies a number of code paths in
particular related to the concept of `IndeterminateComponent` types.
## Overview
This has landed, so we can remove the flag
## Changelog
This change blocks using javascript URLs such as:
```html
<a href="javascript:notfine">p0wned</a>
```
We previously announced dropping support for this via a warning:
> A future version of React will block javascript: URLs as a security
precaution. Use event handlers instead if you can. If you need to
generate unsafe HTML try using dangerouslySetInnerHTML instead.
If false, this ignores text comparison checks during hydration at the
risk of privacy safety.
Since React 18 we recreate the DOM starting from the nearest Suspense
boundary if any of the text content mismatches. This ensures that if we
have nodes that otherwise line up correctly such as if they're the same
type of Component but in a different order, then we don't accidentally
transfer state or attributes to the wrong one.
If we didn't do this e.g. attributes like image src might not line up
with the text. E.g. you might show the wrong profile picture with the
wrong name. However, the main reason we do this is because it's a
security/privacy concern if state from the original node can transfer to
the other one. For example if you start typing into a text field to
reply to a story but then it turns out that the hydration was in a
different order, you might submit that text into a different story than
you intended. Similarly, if you've already clicked an item and that gets
replayed using Action replaying or is synchronously force hydrated -
that click might end up applying to a different item in the list than
you intended. E.g. liking the wrong photo.
Unfortunately a common case where this happens is when Google Translate
is applied to a page. It'll always cause mismatches and recreate the
tree. Most of the time this wouldn't be visible to users because it'd
just recreate to the same thing and then translate again. It can affect
metrics that trace when this hydration happened though.
Meta can use this flag to decide if they favor this perf metric over the
risk to user privacy.
This is similar to the old enableClientRenderFallbackOnTextMismatch flag
except this flag doesn't patch up the text when there's a mismatch.
Because we don't have the patching anymore. The assumption is that it is
safe to ignore the safety concern because we assume it's a match and
therefore favoring not patching it will lead to better perf.
## Summary
Based on
- https://github.com/facebook/react/pull/27903
This PR
- Silence warning in React tests
- Turn on flag
We want to finish cleaning up internal RTR usage, but let's prioritize
the deprecation process. We do this by silencing the internal warning
for now.
## How did you test this change?
`yarn build`
`yarn test ReactHooksInspectionIntegration -b`
## Summary
After realizing that this feature flag is entangled with
`alwaysThrottleRetries`, we're going to undo
https://github.com/facebook/react/pull/28550
## How did you test this change?
```
$ yarn test
$ yarn flow dom-browser
$ yarn flow dom-fb
$ yarn flow fabric
```
## Summary
Creates a new `alwaysThrottleDisappearingFallbacks` feature flag that
gates the changes from https://github.com/facebook/react/pull/26802
(instead of being controlled by `alwaysThrottleRetries`). The values of
this new flag mirror the current values of `alwaysThrottleRetries` such
that there is no behavior difference.
This additional feature flag allows us to incrementally validate the
change (arguably bug fix) from
https://github.com/facebook/react/pull/26802 independently from
`alwaysThrottleRetries`.
## How did you test this change?
```
$ yarn test
$ yarn flow dom-browser
$ yarn flow dom-fb
$ yarn flow fabric
```