From 1a5b014a7ac072d3937e9439f6d038f88c9af838 Mon Sep 17 00:00:00 2001 From: Jan Potoms <2109932+Janpot@users.noreply.github.com> Date: Fri, 20 Sep 2024 18:27:09 +0200 Subject: [PATCH] [code-infra] Enable React compiler eslint plugin (#4121) Co-authored-by: Pedro Ferreira <10789765+apedroferreira@users.noreply.github.com> --- .eslintrc.js | 14 ++++---- docs/pages/toolpad/studio/index.js | 4 +-- .../src/DashboardLayout/DashboardLayout.tsx | 8 +++-- .../NotificationsProvider.tsx | 10 ++++-- .../toolpad-studio/src/utils/useThottled.ts | 34 ------------------- packages/toolpad-utils/src/hooks/useLatest.ts | 12 +++---- 6 files changed, 25 insertions(+), 57 deletions(-) delete mode 100644 packages/toolpad-studio/src/utils/useThottled.ts diff --git a/.eslintrc.js b/.eslintrc.js index 5b5b1650cd0..795d73fa5aa 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -2,8 +2,6 @@ const baseline = require('@mui/monorepo/.eslintrc'); const path = require('path'); const lodash = require('lodash'); -const ENABLE_REACT_COMPILER_PLUGIN = false; - const ALLOWED_LODASH_METHODS = new Set(['throttle', 'debounce', 'set']); const noRestrictedImports = { @@ -33,11 +31,7 @@ const noRestrictedImports = { module.exports = { ...baseline, - plugins: [ - ...baseline.plugins, - ...(ENABLE_REACT_COMPILER_PLUGIN ? ['eslint-plugin-react-compiler'] : []), - 'testing-library', - ], + plugins: [...baseline.plugins, 'eslint-plugin-react-compiler', 'testing-library'], settings: { 'import/resolver': { webpack: { @@ -101,7 +95,7 @@ module.exports = { }, ], 'material-ui/no-hardcoded-labels': 'off', // We are not really translating the docs/website anymore - ...(ENABLE_REACT_COMPILER_PLUGIN ? { 'react-compiler/react-compiler': 'error' } : {}), + 'react-compiler/react-compiler': 'error', }, overrides: [ ...baseline.overrides, @@ -197,5 +191,9 @@ module.exports = { 'no-restricted-imports': ['error', noRestrictedImports], }, }, + { + files: ['packages/toolpad-studio/src/**/*'], + rules: { 'react-compiler/react-compiler': 'off' }, + }, ], }; diff --git a/docs/pages/toolpad/studio/index.js b/docs/pages/toolpad/studio/index.js index b64e7ec6f55..86df5b4068e 100644 --- a/docs/pages/toolpad/studio/index.js +++ b/docs/pages/toolpad/studio/index.js @@ -15,7 +15,7 @@ import CardGrid from '../../../src/components/landing-studio/CardGrid'; import Pricing from '../../../src/components/landing-studio/PricingTable'; import Marquee from '../../../src/components/landing-studio/Marquee'; import features from '../../../data/toolpad/studio/landing/features'; -import useCases from '../../../data/toolpad/studio/landing/useCases'; +import studioUseCases from '../../../data/toolpad/studio/landing/useCases'; import marquee from '../../../data/toolpad/studio/landing/marquee'; import { Headline, @@ -44,7 +44,7 @@ export default function Home() { - + diff --git a/packages/toolpad-core/src/DashboardLayout/DashboardLayout.tsx b/packages/toolpad-core/src/DashboardLayout/DashboardLayout.tsx index 393d6ea66ad..b21df1beee3 100644 --- a/packages/toolpad-core/src/DashboardLayout/DashboardLayout.tsx +++ b/packages/toolpad-core/src/DashboardLayout/DashboardLayout.tsx @@ -416,7 +416,6 @@ function DashboardLayout(props: DashboardLayoutProps) { const [isNavigationFullyExpanded, setIsNavigationFullyExpanded] = React.useState(isNavigationExpanded); - // eslint-disable-next-line consistent-return React.useEffect(() => { if (isNavigationExpanded) { const drawerWidthTransitionTimeout = setTimeout(() => { @@ -427,6 +426,8 @@ function DashboardLayout(props: DashboardLayoutProps) { } setIsNavigationFullyExpanded(false); + + return () => {}; }, [isNavigationExpanded, theme]); const selectedItemIdRef = React.useRef(''); @@ -449,8 +450,9 @@ function DashboardLayout(props: DashboardLayoutProps) { // If useEffect was used, the reset would also happen on the client render after SSR which we don't need React.useMemo(() => { - selectedItemIdRef.current = ''; - // eslint-disable-next-line react-hooks/exhaustive-deps + if (navigation) { + selectedItemIdRef.current = ''; + } }, [navigation]); const isDesktopMini = !disableCollapsibleSidebar && !isDesktopNavigationExpanded; diff --git a/packages/toolpad-core/src/useNotifications/NotificationsProvider.tsx b/packages/toolpad-core/src/useNotifications/NotificationsProvider.tsx index af37a13285c..8a7ab8cabb2 100644 --- a/packages/toolpad-core/src/useNotifications/NotificationsProvider.tsx +++ b/packages/toolpad-core/src/useNotifications/NotificationsProvider.tsx @@ -141,7 +141,12 @@ export interface NotificationsProviderProps { slotProps?: Partial; } -let nextId = 1; +let nextId = 0; +const generateId = () => { + const id = nextId; + nextId += 1; + return id; +}; /** * Provider for Notifications. The subtree of this component can use the `useNotifications` hook to @@ -161,8 +166,7 @@ function NotificationsProvider(props: NotificationsProviderProps) { const [state, setState] = React.useState({ queue: [] }); const show = React.useCallback((message, options = {}) => { - const notificationKey = options.key ?? `::toolpad-internal::notification::${nextId}`; - nextId += 1; + const notificationKey = options.key ?? `::toolpad-internal::notification::${generateId()}`; setState((prev) => { if (prev.queue.some((n) => n.notificationKey === notificationKey)) { // deduplicate by key diff --git a/packages/toolpad-studio/src/utils/useThottled.ts b/packages/toolpad-studio/src/utils/useThottled.ts deleted file mode 100644 index adcbc5936f0..00000000000 --- a/packages/toolpad-studio/src/utils/useThottled.ts +++ /dev/null @@ -1,34 +0,0 @@ -import * as React from 'react'; -/** - * This hook allows you to throttle any fast changing value. The throttle value will only - * update once in the defined time period. Multiple changes to the value within this time - * period are throttled until the delay has passed. - */ -export default function useThrottled(value: T, throttle: number): T { - const [throttledValue, setThrottledValue] = React.useState(value); - const lastUpdate = React.useRef(-Infinity); - - const updateThrottledValue = React.useCallback((newValue: T) => { - lastUpdate.current = Date.now(); - setThrottledValue(newValue); - }, []); - - React.useEffect(() => { - const now = Date.now(); - const elapsed = now - lastUpdate.current; - - if (elapsed > throttle) { - updateThrottledValue(value); - return () => {}; - } - - const delay = throttle - elapsed; - const timeoutId = setTimeout(() => updateThrottledValue(value), delay); - return () => clearTimeout(timeoutId); - }, [value, throttle, updateThrottledValue]); - - const now = Date.now(); - const elapsed = now - lastUpdate.current; - - return elapsed > throttle ? value : throttledValue; -} diff --git a/packages/toolpad-utils/src/hooks/useLatest.ts b/packages/toolpad-utils/src/hooks/useLatest.ts index 3cb3d8ec904..2c29357b97b 100644 --- a/packages/toolpad-utils/src/hooks/useLatest.ts +++ b/packages/toolpad-utils/src/hooks/useLatest.ts @@ -6,13 +6,11 @@ import * as React from 'react'; function useLatest(value: T): T; function useLatest(value: T | null | undefined): T | null | undefined; function useLatest(value: T | null | undefined): T | null | undefined { - const valueRef = React.useRef(value); - React.useEffect(() => { - if (value !== null && value !== undefined) { - valueRef.current = value; - } - }, [value]); - return value ?? valueRef.current; + const [latest, setLatest] = React.useState(value); + if (latest !== value && value !== null && value !== undefined) { + setLatest(value); + } + return value ?? latest; } export default useLatest;