mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-22 04:26:23 +08:00
fix(core): add null checks for timeout refs and event listeners for React 19 compatibility (#9116)
## Description - Add null checks before clearTimeout calls in colorful-fallback.tsx, edgeless.dialog.tsx, and local.dialog.tsx - Fix event listener cleanup in unfolding.tsx - Update tsconfig.jsx to use react-jsx transform ## Testing - [x] Verified type safety improvements for React 19 compatibility - [x] Ensured proper cleanup of event listeners and timeouts - [x] Confirmed no unintended side effects from the changes Link to Devin run: https://app.devin.ai/sessions/2e790f3ea0d84402837ec6c3c6f83e4c
This commit is contained in:
@@ -51,7 +51,7 @@ export const AIOnboardingEdgeless = () => {
|
||||
const generalAIOnboardingOpened = useLiveData(showAIOnboardingGeneral$);
|
||||
const aiSubscription = useLiveData(subscriptionService.subscription.ai$);
|
||||
const globalDialogService = useService(GlobalDialogService);
|
||||
const timeoutRef = useRef<ReturnType<typeof setTimeout>>();
|
||||
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
const mode = useLiveData(editorService.editor.mode$);
|
||||
|
||||
@@ -67,7 +67,9 @@ export const AIOnboardingEdgeless = () => {
|
||||
if (generalAIOnboardingOpened) return;
|
||||
if (notifyId) return;
|
||||
if (mode !== 'edgeless') return;
|
||||
clearTimeout(timeoutRef.current);
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
// try to close local onboarding
|
||||
notify.dismiss(localNotifyId$.value);
|
||||
|
||||
@@ -67,7 +67,7 @@ export const AIOnboardingLocal = () => {
|
||||
const t = useI18n();
|
||||
const authService = useService(AuthService);
|
||||
const notifyId = useLiveData(localNotifyId$);
|
||||
const timeoutRef = useRef<ReturnType<typeof setTimeout>>();
|
||||
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
const loginStatus = useLiveData(authService.session.status$);
|
||||
const notSignedIn = loginStatus !== 'authenticated';
|
||||
@@ -75,7 +75,9 @@ export const AIOnboardingLocal = () => {
|
||||
useEffect(() => {
|
||||
if (!notSignedIn) return;
|
||||
if (notifyId) return;
|
||||
clearTimeout(timeoutRef.current);
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
// try to close edgeless onboarding
|
||||
notify.dismiss(edgelessNotifyId$.value);
|
||||
|
||||
@@ -5,12 +5,12 @@ import { OAuthProviderType } from '@affine/graphql';
|
||||
import track from '@affine/track';
|
||||
import { GithubIcon, GoogleDuotoneIcon } from '@blocksuite/icons/rc';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { type ReactElement, useCallback } from 'react';
|
||||
import { type ReactElement, type SVGAttributes, useCallback } from 'react';
|
||||
|
||||
const OAuthProviderMap: Record<
|
||||
OAuthProviderType,
|
||||
{
|
||||
icon: ReactElement;
|
||||
icon: ReactElement<SVGAttributes<SVGElement>>;
|
||||
}
|
||||
> = {
|
||||
[OAuthProviderType.Google]: {
|
||||
|
||||
@@ -43,7 +43,9 @@ export const EdgelessSwitch = ({
|
||||
const prevStateRef = useRef<EdgelessSwitchState | null>(
|
||||
article.initState ?? null
|
||||
);
|
||||
const enableScrollTimerRef = useRef<ReturnType<typeof setTimeout>>();
|
||||
const enableScrollTimerRef = useRef<ReturnType<typeof setTimeout> | null>(
|
||||
null
|
||||
);
|
||||
const turnOffScalingRef = useRef<() => void>(() => {});
|
||||
|
||||
const [scrollable, setScrollable] = useState(false);
|
||||
|
||||
@@ -33,8 +33,8 @@ export const Unfolding = ({
|
||||
const handler = () => {
|
||||
onChanged?.(fold);
|
||||
};
|
||||
ref.current.addEventListener('transitionend', handler, { once: true });
|
||||
return () => paper?.removeEventListener('transitionend', handler);
|
||||
paper.addEventListener('transitionend', handler, { once: true });
|
||||
return () => paper.removeEventListener('transitionend', handler);
|
||||
}
|
||||
|
||||
return () => null;
|
||||
|
||||
+5
-2
@@ -1,4 +1,7 @@
|
||||
import { InternalLottie } from '@affine/component/internal-lottie';
|
||||
import {
|
||||
type CustomLottieProps,
|
||||
InternalLottie,
|
||||
} from '@affine/component/internal-lottie';
|
||||
import type { HTMLAttributes } from 'react';
|
||||
import type React from 'react';
|
||||
import { cloneElement, useState } from 'react';
|
||||
@@ -10,7 +13,7 @@ type HoverAnimateControllerProps = {
|
||||
active?: boolean;
|
||||
hide?: boolean;
|
||||
trash?: boolean;
|
||||
children: React.ReactElement;
|
||||
children: React.ReactElement<CustomLottieProps>;
|
||||
} & HTMLAttributes<HTMLDivElement>;
|
||||
|
||||
const HoverAnimateController = ({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Collection, Tag } from '@affine/env/filter';
|
||||
import type { DocCollection, DocMeta } from '@blocksuite/affine/store';
|
||||
import type { PropsWithChildren, ReactNode } from 'react';
|
||||
import type { JSX, PropsWithChildren, ReactNode } from 'react';
|
||||
import type { To } from 'react-router-dom';
|
||||
|
||||
export type ListItem = DocMeta | CollectionMeta | TagMeta;
|
||||
|
||||
Reference in New Issue
Block a user