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

fix: remove react-hooks linter suppression #8051

Merged
merged 1 commit into from
Jan 3, 2025
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"check:deps": "pnpm --recursive --parallel exec depcheck",
"check:format": "prettier . --check",
"check:lint": "turbo run lint --continue -- --quiet",
"check:react-compiler": "eslint --cache --no-inline-config --no-eslintrc --ext .cjs,.mjs,.js,.jsx,.ts,.tsx --parser @typescript-eslint/parser --plugin react-compiler --rule 'react-compiler/react-compiler: [warn]' --ignore-path .eslintignore.react-compiler --max-warnings 30 .",
"check:react-compiler": "eslint --cache --no-inline-config --no-eslintrc --ext .cjs,.mjs,.js,.jsx,.ts,.tsx --parser @typescript-eslint/parser --plugin react-compiler --rule 'react-compiler/react-compiler: [warn]' --ignore-path .eslintignore.react-compiler --max-warnings 25 .",
"report:react-compiler-bailout": "eslint --cache --no-inline-config --no-eslintrc --ext .cjs,.mjs,.js,.jsx,.ts,.tsx --parser @typescript-eslint/parser --plugin react-compiler --rule 'react-compiler/react-compiler: [error,{__unstable_donotuse_reportAllBailouts:true}]' --ignore-path .eslintignore.react-compiler -f ./scripts/reactCompilerBailouts.cjs . || true",
"check:test": "run-s test -- --silent",
"check:types": "tsc && turbo run check:types --filter='./packages/*' --filter='./packages/@sanity/*'",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {TrashIcon} from '@sanity/icons'
import {useTelemetry} from '@sanity/telemetry/react'
import {Box, Flex, Switch, Text, useToast} from '@sanity/ui'
import {useCallback, useEffect, useState} from 'react'
import {useEffectEvent} from 'use-effect-event'

import {Button} from '../../../../../ui-components'
import {type ObjectInputProps, set} from '../../../../form'
Expand Down Expand Up @@ -47,46 +48,48 @@ export function FormCreate(props: ObjectInputProps) {
const {data} = useTasks()
const savedTask = data.find((task) => task._id === value._id)

const handleCreatingSuccess = useEffectEvent(() => {
telemetry.log(TaskCreated)
toast.push({
closable: true,
status: 'success',
title: t('form.status.success'),
})

setCreating(false)
if (createMore) {
setViewMode({type: 'create'})
} else {
setActiveTab('subscribed')
}
})
useEffect(() => {
// This useEffect takes care of closing the form when a task entered the "creation" state.
// That action is async and we don't have access to the promise, once the value is updated in the form we will close the form.
if (creating && savedTask?.createdByUser) {
telemetry.log(TaskCreated)
toast.push({
closable: true,
status: 'success',
title: t('form.status.success'),
})

setCreating(false)
if (createMore) {
setViewMode({type: 'create'})
} else {
setActiveTab('subscribed')
}
handleCreatingSuccess()
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [creating, savedTask?.createdByUser])
}, [creating, handleCreatingSuccess, savedTask?.createdByUser])

const handleCreatingTimeout = useEffectEvent(() => {
setCreating(false)
toast.push({
closable: true,
status: 'error',
title: t('form.status.error.creation-failed'),
})
})
useEffect(() => {
// If after 10 seconds the task is still in the "creating" state, show an error and reset the creating state.
let timeoutId: ReturnType<typeof setTimeout> | null = null
if (creating) {
timeoutId = setTimeout(() => {
setCreating(false)
toast.push({
closable: true,
status: 'error',
title: t('form.status.error.creation-failed'),
})
}, 10000)
timeoutId = setTimeout(() => handleCreatingTimeout(), 10000)
}
// Cleanup function to clear the timeout
return () => {
if (timeoutId) clearTimeout(timeoutId)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [creating])
}, [creating, handleCreatingTimeout])

const handleCreate = useCallback(async () => {
setCreating(true)
Expand Down
8 changes: 5 additions & 3 deletions packages/sanity/src/core/tasks/hooks/useActivityLog.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {type TransactionLogEventWithEffects} from '@sanity/types'
import {useCallback, useEffect, useState} from 'react'
import {useEffectEvent} from 'use-effect-event'

import {useClient} from '../../hooks'
import {getJsonStream} from '../../store/_legacy/history/history/getJsonStream'
Expand Down Expand Up @@ -65,10 +66,11 @@ export function useActivityLog(task: TaskDocument): {
[transactionsUrl, token, publishedId],
)

// eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-vars
const handleFetchAndParse = useEffectEvent((rev: string) => fetchAndParse(task))
useEffect(() => {
fetchAndParse(task)
// Task is updated on every change, wait until the revision changes to update the activity log.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [fetchAndParse, task._rev])
handleFetchAndParse(task._rev)
Copy link
Member Author

Choose a reason for hiding this comment

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

Sending the task._rev here is just to make it a valid useEffect dependency in the eyes of eslint-plugin-react-hooks/exhaustive-deps as well as the React Compiler.

}, [handleFetchAndParse, task._rev])
return {changes}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
useDocumentStore,
useTranslation,
} from 'sanity'
import {useEffectEvent} from 'use-effect-event'

import {Delay} from '../../../../components'
import {structureLocaleNamespace} from '../../../../i18n'
Expand Down Expand Up @@ -102,21 +103,23 @@ export const FormView = forwardRef<HTMLDivElement, FormViewProps>(function FormV
}, [documentId, documentStore, documentType, patchChannel])

const hasRev = Boolean(value?._rev)
const handleInitialValue = useEffectEvent(() => {
// this is a workaround for an issue that caused the document pushed to withDocument to get
// stuck at the first initial value.
// This effect is triggered only when the document goes from not having a revision, to getting one
// so it will kick in as soon as the document is received from the backend
patchChannel.publish({
type: 'mutation',
patches: [],
snapshot: value,
})
})
useEffect(() => {
if (hasRev) {
// this is a workaround for an issue that caused the document pushed to withDocument to get
// stuck at the first initial value.
// This effect is triggered only when the document goes from not having a revision, to getting one
// so it will kick in as soon as the document is received from the backend
patchChannel.publish({
type: 'mutation',
patches: [],
snapshot: value,
})
handleInitialValue()
}
// React to changes in hasRev only
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [hasRev])
}, [handleInitialValue, hasRev])

const [formRef, setFormRef] = useState<null | HTMLDivElement>(null)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,10 +247,6 @@ export function DocumentListPaneContent(props: DocumentListPaneContentProps) {
</CommandListBox>
</RootBox>
)
// Explicitly don't include `noDocumentsContent` in the deps array, as it's
// causing a visual bug where the "No documents" message is shown for a split second
// when clearing a search query with no results
Comment on lines -250 to -252
Copy link
Member Author

Choose a reason for hiding this comment

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

I can't reproduce this issue mentioned here, so I think we're good.
In any case, it's not ideal that what initially was just noDocumentsContent being exempt has eventually led to other deps, t and paneTitle, being accidentally omitted.
It demonstrates why it's risky to suppress the linter to begin with 😅

Copy link
Member

Choose a reason for hiding this comment

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

Good call, glad to get rid of hacks like this

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
collapsed,
error,
Expand All @@ -260,11 +256,13 @@ export function DocumentListPaneContent(props: DocumentListPaneContentProps) {
items,
layout,
loadingVariant,
// noDocumentsContent,
noDocumentsContent,
onRetry,
paneTitle,
renderItem,
searchInputElement,
shouldRender,
t,
])

return (
Expand Down
Loading