Skip to content

Commit 14fffc7

Browse files
authored
Merge pull request #3018 from tanem/chore/migrate-eslint-react
chore(deps): replace eslint-plugin-react with @eslint-react/eslint-plugin
2 parents c4892f2 + b552509 commit 14fffc7

8 files changed

Lines changed: 5559 additions & 4400 deletions

File tree

eslint.config.mjs

Lines changed: 13 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,40 @@
1-
import path from 'node:path'
2-
import { fileURLToPath } from 'node:url'
3-
41
import js from '@eslint/js'
2+
import eslintReact from '@eslint-react/eslint-plugin'
53
import eslintConfigPrettier from 'eslint-config-prettier'
6-
import react from 'eslint-plugin-react'
4+
import perfectionist from 'eslint-plugin-perfectionist'
75
import reactHooks from 'eslint-plugin-react-hooks'
86
import simpleImportSort from 'eslint-plugin-simple-import-sort'
97
import globals from 'globals'
108
import tseslint from 'typescript-eslint'
119

12-
const __filename = fileURLToPath(import.meta.url)
13-
const __dirname = path.dirname(__filename)
14-
1510
export default tseslint.config(
1611
{
1712
ignores: ['**/compiled/', '**/coverage/', '**/dist/', '**/node_modules/'],
1813
},
1914
js.configs.recommended,
2015
...tseslint.configs.recommended,
21-
react.configs.flat.recommended,
22-
eslintConfigPrettier,
16+
eslintReact.configs['recommended-typescript'],
2317
{
24-
languageOptions: {
25-
parserOptions: {
26-
ecmaFeatures: {
27-
jsx: true,
28-
},
29-
project: path.join(__dirname, 'tsconfig.eslint.json'),
30-
},
31-
},
32-
3318
plugins: {
19+
perfectionist,
3420
'react-hooks': reactHooks,
3521
'simple-import-sort': simpleImportSort,
3622
},
3723

3824
rules: {
39-
'react-hooks/exhaustive-deps': 'warn',
40-
'react-hooks/rules-of-hooks': 'error',
41-
'react/jsx-sort-props': 'error',
42-
'react/jsx-uses-react': 'off',
43-
'react/react-in-jsx-scope': 'off',
25+
...reactHooks.configs['recommended-latest'].rules,
26+
// eslint-plugin-react-hooks (above) is the source of truth for hooks
27+
// rules, since it's backed by the React team's compiler. Disable the
28+
// overlapping rules from @eslint-react/eslint-plugin's recommended
29+
// config to avoid duplicate reports.
30+
'@eslint-react/exhaustive-deps': 'off',
31+
'@eslint-react/rules-of-hooks': 'off',
32+
'perfectionist/sort-jsx-props': 'error',
4433
'simple-import-sort/exports': 'error',
4534
'simple-import-sort/imports': 'error',
4635
'sort-imports': 'off',
4736
'sort-keys': 'error',
4837
},
49-
50-
settings: {
51-
react: {
52-
version: 'detect',
53-
},
54-
},
5538
},
5639
{
5740
files: ['**/*.js'],
@@ -61,7 +44,6 @@ export default tseslint.config(
6144
},
6245
},
6346
rules: {
64-
'@typescript-eslint/explicit-module-boundary-types': 'off',
6547
'@typescript-eslint/no-require-imports': 'off',
6648
},
6749
},
@@ -73,17 +55,5 @@ export default tseslint.config(
7355
},
7456
},
7557
},
76-
{
77-
files: ['examples/**/*'],
78-
rules: {
79-
'@typescript-eslint/explicit-module-boundary-types': 'off',
80-
'react/no-unknown-property': [
81-
'error',
82-
{
83-
ignore: ['jsx'],
84-
},
85-
],
86-
'react/prop-types': 'off',
87-
},
88-
},
58+
eslintConfigPrettier,
8959
)

examples/next-app-router/components/NavigationProgress.tsx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import { usePathname, useSearchParams } from 'next/navigation'
44
import {
55
createContext,
66
Suspense,
7+
use,
78
useCallback,
8-
useContext,
99
useEffect,
1010
useRef,
1111
useState,
@@ -21,7 +21,7 @@ const NavigationProgressContext =
2121
createContext<NavigationProgressContextType | null>(null)
2222

2323
export function useNavigationProgress() {
24-
const context = useContext(NavigationProgressContext)
24+
const context = use(NavigationProgressContext)
2525
if (!context) {
2626
throw new Error(
2727
'useNavigationProgress must be used within <NavigationProgress>',
@@ -34,12 +34,12 @@ export function useNavigationProgress() {
3434
function NavigationComplete({ onComplete }: { onComplete: () => void }) {
3535
const pathname = usePathname()
3636
const searchParams = useSearchParams()
37-
const currentUrl = useRef(pathname + searchParams.toString())
37+
const currentUrlRef = useRef(pathname + searchParams.toString())
3838

3939
useEffect(() => {
4040
const newUrl = pathname + searchParams.toString()
41-
if (newUrl !== currentUrl.current) {
42-
currentUrl.current = newUrl
41+
if (newUrl !== currentUrlRef.current) {
42+
currentUrlRef.current = newUrl
4343
onComplete()
4444
}
4545
}, [pathname, searchParams, onComplete])
@@ -57,6 +57,10 @@ export default function NavigationProgress({
5757
const [isRouteChanging, setIsRouteChanging] = useState(false)
5858
const [loadingKey, setLoadingKey] = useState(0)
5959

60+
// Read directly during render to lazily create a stable context value
61+
// once; useRef's initial-value argument is only ever used on the very
62+
// first render.
63+
// eslint-disable-next-line react-hooks/refs
6064
const contextValue = useRef<NavigationProgressContextType>({
6165
start: () => {
6266
setIsRouteChanging(true)
@@ -67,12 +71,12 @@ export default function NavigationProgress({
6771
const handleComplete = useCallback(() => setIsRouteChanging(false), [])
6872

6973
return (
70-
<NavigationProgressContext.Provider value={contextValue}>
74+
<NavigationProgressContext value={contextValue}>
7175
<Loading isRouteChanging={isRouteChanging} key={loadingKey} />
7276
<Suspense>
7377
<NavigationComplete onComplete={handleComplete} />
7478
</Suspense>
7579
{children}
76-
</NavigationProgressContext.Provider>
80+
</NavigationProgressContext>
7781
)
7882
}

0 commit comments

Comments
 (0)