-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
switch
useRenderGuard
to an approach not accessing React's internals (
- Loading branch information
Showing
4 changed files
with
45 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@apollo/client": patch | ||
--- | ||
|
||
switch `useRenderGuard` to an approach not accessing React's internals |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
{ | ||
"dist/apollo-client.min.cjs": 39620, | ||
"dist/apollo-client.min.cjs": 39561, | ||
"import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 32821 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,45 @@ | ||
import * as React from "rehackt"; | ||
|
||
function getRenderDispatcher() { | ||
return (React as any).__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED | ||
?.ReactCurrentDispatcher?.current; | ||
} | ||
|
||
let RenderDispatcher: unknown = null; | ||
let Ctx: React.Context<null>; | ||
|
||
/* | ||
Relay does this too, so we hope this is safe. | ||
https://github.com/facebook/relay/blob/8651fbca19adbfbb79af7a3bc40834d105fd7747/packages/react-relay/relay-hooks/loadQuery.js#L90-L98 | ||
*/ | ||
function noop() {} | ||
export function useRenderGuard() { | ||
// eslint-disable-next-line react-compiler/react-compiler | ||
RenderDispatcher = getRenderDispatcher(); | ||
if (!Ctx) { | ||
// we want the intialization to be lazy because `createContext` would error on import in a RSC | ||
Ctx = React.createContext(null); | ||
} | ||
|
||
return React.useCallback( | ||
/** | ||
* @returns true if the hook was called during render | ||
*/ () => { | ||
const orig = console.error; | ||
try { | ||
console.error = noop; | ||
|
||
return React.useCallback(() => { | ||
return ( | ||
RenderDispatcher != null && RenderDispatcher === getRenderDispatcher() | ||
); | ||
}, []); | ||
/** | ||
* `useContext` can be called conditionally during render, so this is safe. | ||
* (Also, during render we would want to throw as a reaction to this anyways, so it | ||
* wouldn't even matter if we got the order of hooks mixed up...) | ||
* | ||
* They cannot however be called outside of Render, and that's what we're testing here. | ||
* | ||
* Different versions of React have different behaviour on an invalid hook call: | ||
* | ||
* React 16.8 - 17: throws an error | ||
* https://github.com/facebook/react/blob/2b93d686e359c7afa299e2ec5cf63160a32a1155/packages/react/src/ReactHooks.js#L18-L26 | ||
* | ||
* React 18 & 19: `console.error` in development, then `resolveDispatcher` returns `null` and a member access on `null` throws. | ||
* https://github.com/facebook/react/blob/58e8304483ebfadd02a295339b5e9a989ac98c6e/packages/react/src/ReactHooks.js#L28-L35 | ||
*/ | ||
React["useContext" /* hide this from the linter */](Ctx); | ||
return true; | ||
} catch (e) { | ||
return false; | ||
} finally { | ||
console.error = orig; | ||
} | ||
}, | ||
[] | ||
); | ||
} |