From 2f5f0978ad7abcba2a37e44ec4baa486e4692468 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 13 Jan 2025 14:54:42 +0000 Subject: [PATCH] Type fixes for react v19 compatibility (#2937) --- src/App.tsx | 2 +- src/ClientContext.tsx | 1 + src/auth/useInteractiveRegistration.ts | 2 +- src/auth/useRecaptcha.ts | 2 +- src/grid/TileWrapper.tsx | 8 +++++++- src/input/Input.tsx | 1 + src/input/StarRatingInput.tsx | 2 +- src/livekit/MediaDevicesContext.tsx | 1 + src/reactions/useReactionsSender.tsx | 1 + src/room/GroupCallView.tsx | 4 ++-- src/room/InCallView.tsx | 1 + src/room/LobbyView.tsx | 2 +- src/room/RoomPage.tsx | 9 ++++++++- src/room/useLoadGroupCall.ts | 2 +- src/settings/RageshakeButton.tsx | 2 +- src/useInitial.ts | 3 ++- src/useReactiveState.ts | 4 ++-- 17 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 62dc5c8f..344858af 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only Please see LICENSE in the repository root for full details. */ -import { type FC, Suspense, useEffect, useState } from "react"; +import { type FC, type JSX, Suspense, useEffect, useState } from "react"; import { BrowserRouter, Route, useLocation, Routes } from "react-router-dom"; import * as Sentry from "@sentry/react"; import { TooltipProvider } from "@vector-im/compound-web"; diff --git a/src/ClientContext.tsx b/src/ClientContext.tsx index 791005bb..dbf8a3fd 100644 --- a/src/ClientContext.tsx +++ b/src/ClientContext.tsx @@ -14,6 +14,7 @@ import { useContext, useRef, useMemo, + type JSX, } from "react"; import { useNavigate } from "react-router-dom"; import { logger } from "matrix-js-sdk/src/logger"; diff --git a/src/auth/useInteractiveRegistration.ts b/src/auth/useInteractiveRegistration.ts index d6568ede..861f543d 100644 --- a/src/auth/useInteractiveRegistration.ts +++ b/src/auth/useInteractiveRegistration.ts @@ -39,7 +39,7 @@ export const useInteractiveRegistration = ( undefined, ); - const authClient = useRef(); + const authClient = useRef(undefined); if (!authClient.current) { authClient.current = createClient({ baseUrl: Config.defaultHomeserverUrl()!, diff --git a/src/auth/useRecaptcha.ts b/src/auth/useRecaptcha.ts index f6b07c69..f04685c3 100644 --- a/src/auth/useRecaptcha.ts +++ b/src/auth/useRecaptcha.ts @@ -32,7 +32,7 @@ export function useRecaptcha(sitekey?: string): { } { const { t } = useTranslation(); const [recaptchaId] = useState(() => randomString(16)); - const promiseRef = useRef(); + const promiseRef = useRef(undefined); useEffect(() => { if (!sitekey) return; diff --git a/src/grid/TileWrapper.tsx b/src/grid/TileWrapper.tsx index a2eebd43..45e1feb9 100644 --- a/src/grid/TileWrapper.tsx +++ b/src/grid/TileWrapper.tsx @@ -5,7 +5,13 @@ SPDX-License-Identifier: AGPL-3.0-only Please see LICENSE in the repository root for full details. */ -import { type ComponentType, memo, type RefObject, useRef } from "react"; +import { + type ComponentType, + type JSX, + memo, + type RefObject, + useRef, +} from "react"; import { type EventTypes, type Handler, useDrag } from "@use-gesture/react"; import { type SpringValue } from "@react-spring/web"; import classNames from "classnames"; diff --git a/src/input/Input.tsx b/src/input/Input.tsx index 761988ad..c63aaa88 100644 --- a/src/input/Input.tsx +++ b/src/input/Input.tsx @@ -12,6 +12,7 @@ import { forwardRef, type ReactNode, useId, + type JSX, } from "react"; import classNames from "classnames"; diff --git a/src/input/StarRatingInput.tsx b/src/input/StarRatingInput.tsx index e862e820..e5885801 100644 --- a/src/input/StarRatingInput.tsx +++ b/src/input/StarRatingInput.tsx @@ -4,7 +4,7 @@ Copyright 2023, 2024 New Vector Ltd. SPDX-License-Identifier: AGPL-3.0-only Please see LICENSE in the repository root for full details. */ -import { useState } from "react"; +import { useState, type JSX } from "react"; import { useTranslation } from "react-i18next"; import styles from "./StarRatingInput.module.css"; diff --git a/src/livekit/MediaDevicesContext.tsx b/src/livekit/MediaDevicesContext.tsx index 44e8a037..7cf001a9 100644 --- a/src/livekit/MediaDevicesContext.tsx +++ b/src/livekit/MediaDevicesContext.tsx @@ -14,6 +14,7 @@ import { useMemo, useRef, useState, + type JSX, } from "react"; import { createMediaDeviceObserver } from "@livekit/components-core"; import { map, startWith } from "rxjs"; diff --git a/src/reactions/useReactionsSender.tsx b/src/reactions/useReactionsSender.tsx index cb70bd87..627fdbe9 100644 --- a/src/reactions/useReactionsSender.tsx +++ b/src/reactions/useReactionsSender.tsx @@ -12,6 +12,7 @@ import { type ReactNode, useCallback, useMemo, + type JSX, } from "react"; import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; import { logger } from "matrix-js-sdk/src/logger"; diff --git a/src/room/GroupCallView.tsx b/src/room/GroupCallView.tsx index ba4bf328..c18d91cd 100644 --- a/src/room/GroupCallView.tsx +++ b/src/room/GroupCallView.tsx @@ -154,11 +154,11 @@ export const GroupCallView: FC = ({ ); const deviceContext = useMediaDevices(); - const latestDevices = useRef(); + const latestDevices = useRef(undefined); latestDevices.current = deviceContext; // TODO: why do we use a ref here instead of using muteStates directly? - const latestMuteStates = useRef(); + const latestMuteStates = useRef(undefined); latestMuteStates.current = muteStates; useEffect(() => { diff --git a/src/room/InCallView.tsx b/src/room/InCallView.tsx index c7dcf00c..56dadd86 100644 --- a/src/room/InCallView.tsx +++ b/src/room/InCallView.tsx @@ -23,6 +23,7 @@ import { useMemo, useRef, useState, + type JSX, } from "react"; import useMeasure from "react-use-measure"; import { type MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; diff --git a/src/room/LobbyView.tsx b/src/room/LobbyView.tsx index 027b4d06..ff455d39 100644 --- a/src/room/LobbyView.tsx +++ b/src/room/LobbyView.tsx @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only Please see LICENSE in the repository root for full details. */ -import { type FC, useCallback, useMemo, useState } from "react"; +import { type FC, useCallback, useMemo, useState, type JSX } from "react"; import { useTranslation } from "react-i18next"; import { type MatrixClient } from "matrix-js-sdk/src/matrix"; import { Button } from "@vector-im/compound-web"; diff --git a/src/room/RoomPage.tsx b/src/room/RoomPage.tsx index d8973c20..f7aad38d 100644 --- a/src/room/RoomPage.tsx +++ b/src/room/RoomPage.tsx @@ -5,7 +5,14 @@ SPDX-License-Identifier: AGPL-3.0-only Please see LICENSE in the repository root for full details. */ -import { type FC, useEffect, useState, type ReactNode, useRef } from "react"; +import { + type FC, + useEffect, + useState, + type ReactNode, + useRef, + type JSX, +} from "react"; import { logger } from "matrix-js-sdk/src/logger"; import { useTranslation } from "react-i18next"; import { CheckIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; diff --git a/src/room/useLoadGroupCall.ts b/src/room/useLoadGroupCall.ts index 5edf49d7..bd36f4e2 100644 --- a/src/room/useLoadGroupCall.ts +++ b/src/room/useLoadGroupCall.ts @@ -122,7 +122,7 @@ export const useLoadGroupCall = ( viaServers: string[], ): GroupCallStatus => { const [state, setState] = useState({ kind: "loading" }); - const activeRoom = useRef(); + const activeRoom = useRef(undefined); const { t } = useTranslation(); const bannedError = useCallback( diff --git a/src/settings/RageshakeButton.tsx b/src/settings/RageshakeButton.tsx index fa17b788..4dda747f 100644 --- a/src/settings/RageshakeButton.tsx +++ b/src/settings/RageshakeButton.tsx @@ -6,7 +6,7 @@ Please see LICENSE in the repository root for full details. */ import { useTranslation } from "react-i18next"; -import { type FC, useCallback } from "react"; +import { type FC, useCallback, type JSX } from "react"; import { Button } from "@vector-im/compound-web"; import { logger } from "matrix-js-sdk/src/logger"; diff --git a/src/useInitial.ts b/src/useInitial.ts index 0a49d004..5f947d3e 100644 --- a/src/useInitial.ts +++ b/src/useInitial.ts @@ -11,7 +11,8 @@ import { useRef } from "react"; * React hook that returns the value given on the initial render. */ export function useInitial(getValue: () => T): T { - const ref = useRef<{ value: T }>(); + const ref = useRef<{ value: T }>(undefined); + // only evaluate `getValue` if the ref is undefined ref.current ??= { value: getValue() }; return ref.current.value; } diff --git a/src/useReactiveState.ts b/src/useReactiveState.ts index 2a58d33a..09327c7c 100644 --- a/src/useReactiveState.ts +++ b/src/useReactiveState.ts @@ -23,9 +23,9 @@ export const useReactiveState = ( updateFn: (prevState?: T) => T, deps: DependencyList, ): [T, Dispatch>] => { - const state = useRef(); + const state = useRef(undefined); if (state.current === undefined) state.current = updateFn(); - const prevDeps = useRef(); + const prevDeps = useRef(undefined); // Since we store the state in a ref, we use this counter to force an update // when someone calls setState