Skip to content
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

Reuse request so that a ReadableStream body does not become disturbed #26771

Merged
merged 5 commits into from
May 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion packages/react/src/ReactFetch.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,13 @@ if (enableCache && enableFetchInstrumentation) {
url = resource;
} else {
// Normalize the request.
const request = new Request(resource, options);
// if resource is not a string or a URL (its an instance of Request)
// then do not instantiate a new Request but instead
// reuse the request as to not disturb the body in the event it's a ReadableStream.
const request =
typeof resource === 'string' || resource instanceof URL
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could in theory be a URL object from a different iframe/realm which is a bit annoying.

? new Request(resource, options)
: resource;
if (
(request.method !== 'GET' && request.method !== 'HEAD') ||
// $FlowFixMe[prop-missing]: keepalive is real
Expand Down
16 changes: 16 additions & 0 deletions packages/react/src/__tests__/ReactFetch-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,22 @@ describe('ReactFetch', () => {
expect(fetchCount).toBe(1);
});

// @gate enableFetchInstrumentation && enableCache
it('can dedupe fetches using URL and not', async () => {
const url = 'http://example.com/';
function Component() {
const response = use(fetch(url));
const text = use(response.text());
const response2 = use(fetch(new URL(url)));
const text2 = use(response2.text());
return text + ' ' + text2;
}
expect(await render(Component)).toMatchInlineSnapshot(
`"GET ${url} [] GET ${url} []"`,
);
expect(fetchCount).toBe(1);
});

it('can opt-out of deduping fetches inside of render with custom signal', async () => {
const controller = new AbortController();
function useCustomHook() {
Expand Down