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

[utils] Fix "useId" & "useSyncExternalStore" imports to not be statically analyzable #43360

Merged
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
7 changes: 4 additions & 3 deletions packages/mui-system/src/useMediaQuery/useMediaQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export interface UseMediaQueryOptions {
ssrMatchMedia?: (query: string) => { matches: boolean };
}

// TODO React 17: Remove `useMediaQueryOld` once React 17 support is removed
function useMediaQueryOld(
query: string,
defaultMatches: boolean,
Expand Down Expand Up @@ -71,8 +72,9 @@ function useMediaQueryOld(
return match;
}

// eslint-disable-next-line no-useless-concat -- Workaround for https://github.com/webpack/webpack/issues/14814
const maybeReactUseSyncExternalStore: undefined | any = (React as any)['useSyncExternalStore' + ''];
// See https://github.com/mui/material-ui/issues/41190#issuecomment-2040873379 for why
const safeReact = { ...React };
const maybeReactUseSyncExternalStore: undefined | any = safeReact.useSyncExternalStore;

function useMediaQueryNew(
query: string,
Expand Down Expand Up @@ -148,7 +150,6 @@ export default function useMediaQuery<Theme = unknown>(
let query = typeof queryInput === 'function' ? queryInput(theme) : queryInput;
query = query.replace(/^@media( ?)/m, '');

// TODO: Drop `useMediaQueryOld` and use `use-sync-external-store` shim in `useMediaQueryNew` once the package is stable
const useMediaQueryImplementation =
maybeReactUseSyncExternalStore !== undefined ? useMediaQueryNew : useMediaQueryOld;
const match = useMediaQueryImplementation(
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-utils/src/useId/useId.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react';
import { expect } from 'chai';
import { createRenderer, screen } from '@mui/internal-test-utils';
import useId from './useId';
import useId from '@mui/utils/useId';

describe('useId', () => {
const { render, renderToString } = createRenderer();
Expand Down
10 changes: 8 additions & 2 deletions packages/mui-utils/src/useId/useId.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import * as React from 'react';

let globalId = 0;

// TODO React 17: Remove `useGlobalId` once React 17 support is removed
function useGlobalId(idOverride?: string): string | undefined {
const [defaultId, setDefaultId] = React.useState(idOverride);
const id = idOverride || defaultId;
Expand All @@ -18,19 +20,23 @@ function useGlobalId(idOverride?: string): string | undefined {
return id;
}

// downstream bundlers may remove unnecessary concatenation, but won't remove toString call -- Workaround for https://github.com/webpack/webpack/issues/14814
const maybeReactUseId: undefined | (() => string) = (React as any)['useId'.toString()];
// See https://github.com/mui/material-ui/issues/41190#issuecomment-2040873379 for why
const safeReact = { ...React };
const maybeReactUseId: undefined | (() => string) = safeReact.useId;

/**
*
* @example <div id={useId()} />
* @param idOverride
* @returns {string}
*/
export default function useId(idOverride?: string): string | undefined {
// React.useId() is only available from React 17.0.0.
if (maybeReactUseId !== undefined) {
const reactId = maybeReactUseId();
return idOverride ?? reactId;
}

// TODO: uncomment once we enable eslint-plugin-react-compiler // eslint-disable-next-line react-compiler/react-compiler
// eslint-disable-next-line react-hooks/rules-of-hooks -- `React.useId` is invariant at runtime.
return useGlobalId(idOverride);
Expand Down