Enable react-compiler eslint to spot antipatterns (#28652)
* Switch to React18 useId Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Enable react-compiler eslint Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix an easy one Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Disable in tests Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix usage of useRef as memoization Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix mutation of external values in hooks Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Make React compiler happy about some frankly non-issues Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix MapMock Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Revert MemberListViewModel.tsx changes and disable linter per line Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Make viewmodel compatible with react-compiler linter - Remove searchQuery ref/state and instead pass this query to the loadMember function. - Now we no longer need a separate search function --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> Co-authored-by: R Midhun Suresh <hi@midhun.dev>
This commit is contained in:
committed by
GitHub
parent
e5ca7954c8
commit
ef1597ff2d
@@ -58,11 +58,10 @@ const EffectsOverlay: FunctionComponent<IProps> = ({ roomWidth }) => {
|
||||
if (canvas) canvas.height = UIStore.instance.windowHeight;
|
||||
UIStore.instance.on(UI_EVENTS.Resize, resize);
|
||||
|
||||
const currentEffects = effectsRef.current; // this is not a react node ref, warning can be safely ignored
|
||||
return () => {
|
||||
dis.unregister(dispatcherRef);
|
||||
UIStore.instance.off(UI_EVENTS.Resize, resize);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const currentEffects = effectsRef.current; // this is not a react node ref, warning can be safely ignored
|
||||
for (const effect in currentEffects) {
|
||||
const effectModule: ICanvasEffect = currentEffects.get(effect)!;
|
||||
if (effectModule && effectModule.isRunning) {
|
||||
|
||||
@@ -6,12 +6,12 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import React, { RefObject } from "react";
|
||||
|
||||
import UIStore, { UI_EVENTS } from "../../../stores/UIStore";
|
||||
|
||||
interface IProps {
|
||||
sensor: Element;
|
||||
sensor: RefObject<Element>;
|
||||
breakpoint: number;
|
||||
onMeasurement(narrow: boolean): void;
|
||||
}
|
||||
@@ -35,14 +35,14 @@ export default class Measured extends React.PureComponent<IProps> {
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: Readonly<IProps>): void {
|
||||
const previous = prevProps.sensor;
|
||||
const current = this.props.sensor;
|
||||
const previous = prevProps.sensor.current;
|
||||
const current = this.props.sensor.current;
|
||||
if (previous === current) return;
|
||||
if (previous) {
|
||||
UIStore.instance.stopTrackingElementDimensions(`Measured${this.instanceId}`);
|
||||
}
|
||||
if (current) {
|
||||
UIStore.instance.trackElementDimensions(`Measured${this.instanceId}`, this.props.sensor);
|
||||
UIStore.instance.trackElementDimensions(`Measured${this.instanceId}`, this.props.sensor.current);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -213,7 +213,7 @@ export default class TimelineCard extends React.Component<IProps, IState> {
|
||||
header={_t("right_panel|video_room_chat|title")}
|
||||
ref={this.card}
|
||||
>
|
||||
{this.card.current && <Measured sensor={this.card.current} onMeasurement={this.onMeasurement} />}
|
||||
<Measured sensor={this.card} onMeasurement={this.onMeasurement} />
|
||||
<div className="mx_TimelineCard_timeline">
|
||||
{jumpToBottom}
|
||||
<TimelinePanel
|
||||
|
||||
@@ -109,6 +109,7 @@ export function ReadReceiptGroup({
|
||||
readReceiptPosition = readReceiptMap[userId];
|
||||
if (!readReceiptPosition) {
|
||||
readReceiptPosition = {};
|
||||
// eslint-disable-next-line react-compiler/react-compiler
|
||||
readReceiptMap[userId] = readReceiptPosition;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useRef, useState } from "react";
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { EventType, KnownMembership, MatrixEvent, Room, RoomStateEvent, RoomMember } from "matrix-js-sdk/src/matrix";
|
||||
import { CryptoApi, CryptoEvent, UserVerificationStatus } from "matrix-js-sdk/src/crypto-api";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
@@ -213,9 +213,11 @@ export const UserIdentityWarning: React.FC<UserIdentityWarningProps> = ({ room }
|
||||
initialisedRef.current = InitialisationStatus.Completed;
|
||||
}, [crypto, room, addMembersWhoNeedApproval, updateCurrentPrompt]);
|
||||
|
||||
loadMembers().catch((e) => {
|
||||
logger.error("Error initialising UserIdentityWarning:", e);
|
||||
});
|
||||
useEffect(() => {
|
||||
loadMembers().catch((e) => {
|
||||
logger.error("Error initialising UserIdentityWarning:", e);
|
||||
});
|
||||
}, [loadMembers]);
|
||||
|
||||
// When a user's verification status changes, we check if they need to be
|
||||
// added/removed from the set of members needing approval.
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { ForwardedRef, forwardRef, MutableRefObject, useRef } from "react";
|
||||
import React, { ForwardedRef, forwardRef, MutableRefObject, useMemo } from "react";
|
||||
import classNames from "classnames";
|
||||
|
||||
import EditorStateTransfer from "../../../../utils/EditorStateTransfer";
|
||||
@@ -44,7 +44,7 @@ export default function EditWysiwygComposer({
|
||||
className,
|
||||
...props
|
||||
}: EditWysiwygComposerProps): JSX.Element {
|
||||
const defaultContextValue = useRef(getDefaultContextValue({ editorStateTransfer }));
|
||||
const defaultContextValue = useMemo(() => getDefaultContextValue({ editorStateTransfer }), [editorStateTransfer]);
|
||||
const initialContent = useInitialContent(editorStateTransfer);
|
||||
const isReady = !editorStateTransfer || initialContent !== undefined;
|
||||
|
||||
@@ -55,7 +55,7 @@ export default function EditWysiwygComposer({
|
||||
}
|
||||
|
||||
return (
|
||||
<ComposerContext.Provider value={defaultContextValue.current}>
|
||||
<ComposerContext.Provider value={defaultContextValue}>
|
||||
<WysiwygComposer
|
||||
className={classNames("mx_EditWysiwygComposer", className)}
|
||||
initialContent={initialContent}
|
||||
|
||||
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { ForwardedRef, forwardRef, MutableRefObject, useRef } from "react";
|
||||
import React, { ForwardedRef, forwardRef, MutableRefObject, useMemo } from "react";
|
||||
import { IEventRelation } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { useWysiwygSendActionHandler } from "./hooks/useWysiwygSendActionHandler";
|
||||
@@ -52,10 +52,13 @@ export default function SendWysiwygComposer({
|
||||
...props
|
||||
}: SendWysiwygComposerProps): JSX.Element {
|
||||
const Composer = isRichTextEnabled ? WysiwygComposer : PlainTextComposer;
|
||||
const defaultContextValue = useRef(getDefaultContextValue({ eventRelation: props.eventRelation }));
|
||||
const defaultContextValue = useMemo(
|
||||
() => getDefaultContextValue({ eventRelation: props.eventRelation }),
|
||||
[props.eventRelation],
|
||||
);
|
||||
|
||||
return (
|
||||
<ComposerContext.Provider value={defaultContextValue.current}>
|
||||
<ComposerContext.Provider value={defaultContextValue}>
|
||||
<Composer
|
||||
className="mx_SendWysiwygComposer"
|
||||
leftComponent={e2eStatus && <E2EIcon status={e2eStatus} />}
|
||||
|
||||
@@ -21,6 +21,7 @@ export function useComposerFunctions(
|
||||
() => ({
|
||||
clear: () => {
|
||||
if (ref.current) {
|
||||
// eslint-disable-next-line react-compiler/react-compiler
|
||||
ref.current.innerHTML = "";
|
||||
}
|
||||
},
|
||||
|
||||
@@ -12,6 +12,7 @@ export function usePlainTextInitialization(initialContent = "", ref: RefObject<H
|
||||
useEffect(() => {
|
||||
// always read and write the ref.current using .innerHTML for consistency in linebreak and HTML entity handling
|
||||
if (ref.current) {
|
||||
// eslint-disable-next-line react-compiler/react-compiler
|
||||
ref.current.innerHTML = initialContent;
|
||||
}
|
||||
}, [ref, initialContent]);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { ChangeEvent, JSX, useCallback, useMemo, useRef, useState } from "react";
|
||||
import React, { ChangeEvent, JSX, useCallback, useMemo, useState } from "react";
|
||||
import {
|
||||
InlineField,
|
||||
ToggleControl,
|
||||
@@ -39,12 +39,12 @@ import { useSettingValue } from "../../../hooks/useSettings";
|
||||
*/
|
||||
export function ThemeChoicePanel(): JSX.Element {
|
||||
const themeState = useTheme();
|
||||
const themeWatcher = useRef(new ThemeWatcher());
|
||||
const themeWatcher = useMemo(() => new ThemeWatcher(), []);
|
||||
const customThemeEnabled = useSettingValue("feature_custom_themes");
|
||||
|
||||
return (
|
||||
<SettingsSubsection heading={_t("common|theme")} legacy={false} data-testid="themePanel">
|
||||
{themeWatcher.current.isSystemThemeSupported() && (
|
||||
{themeWatcher.isSystemThemeSupported() && (
|
||||
<SystemTheme systemThemeActivated={themeState.systemThemeActivated} />
|
||||
)}
|
||||
<ThemeSelectors theme={themeState.theme} disabled={themeState.systemThemeActivated} />
|
||||
|
||||
@@ -8,6 +8,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
|
||||
import React, { useCallback, useMemo, useState } from "react";
|
||||
import { JoinRule, EventType, RoomState, Room } from "matrix-js-sdk/src/matrix";
|
||||
import { RoomPowerLevelsEventContent } from "matrix-js-sdk/src/types";
|
||||
|
||||
import { _t } from "../../../../../languageHandler";
|
||||
import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch";
|
||||
@@ -24,48 +25,49 @@ interface ElementCallSwitchProps {
|
||||
|
||||
const ElementCallSwitch: React.FC<ElementCallSwitchProps> = ({ room }) => {
|
||||
const isPublic = useMemo(() => room.getJoinRule() === JoinRule.Public, [room]);
|
||||
const [content, events, maySend] = useRoomState(
|
||||
const [content, maySend] = useRoomState(
|
||||
room,
|
||||
useCallback(
|
||||
(state: RoomState) => {
|
||||
const content = state?.getStateEvents(EventType.RoomPowerLevels, "")?.getContent();
|
||||
const content = state
|
||||
?.getStateEvents(EventType.RoomPowerLevels, "")
|
||||
?.getContent<RoomPowerLevelsEventContent>();
|
||||
return [
|
||||
content ?? {},
|
||||
content?.["events"] ?? {},
|
||||
state?.maySendStateEvent(EventType.RoomPowerLevels, room.client.getSafeUserId()),
|
||||
];
|
||||
] as const;
|
||||
},
|
||||
[room.client],
|
||||
),
|
||||
);
|
||||
|
||||
const [elementCallEnabled, setElementCallEnabled] = useState<boolean>(() => {
|
||||
return events[ElementCall.MEMBER_EVENT_TYPE.name] === 0;
|
||||
return content.events?.[ElementCall.MEMBER_EVENT_TYPE.name] === 0;
|
||||
});
|
||||
|
||||
const onChange = useCallback(
|
||||
(enabled: boolean): void => {
|
||||
setElementCallEnabled(enabled);
|
||||
|
||||
// Take a copy to avoid mutating the original
|
||||
const newContent = { events: {}, ...content };
|
||||
|
||||
if (enabled) {
|
||||
const userLevel = events[EventType.RoomMessage] ?? content.users_default ?? 0;
|
||||
const userLevel = newContent.events[EventType.RoomMessage] ?? content.users_default ?? 0;
|
||||
const moderatorLevel = content.kick ?? 50;
|
||||
|
||||
events[ElementCall.CALL_EVENT_TYPE.name] = isPublic ? moderatorLevel : userLevel;
|
||||
events[ElementCall.MEMBER_EVENT_TYPE.name] = userLevel;
|
||||
newContent.events[ElementCall.CALL_EVENT_TYPE.name] = isPublic ? moderatorLevel : userLevel;
|
||||
newContent.events[ElementCall.MEMBER_EVENT_TYPE.name] = userLevel;
|
||||
} else {
|
||||
const adminLevel = events[EventType.RoomPowerLevels] ?? content.state_default ?? 100;
|
||||
const adminLevel = newContent.events[EventType.RoomPowerLevels] ?? content.state_default ?? 100;
|
||||
|
||||
events[ElementCall.CALL_EVENT_TYPE.name] = adminLevel;
|
||||
events[ElementCall.MEMBER_EVENT_TYPE.name] = adminLevel;
|
||||
newContent.events[ElementCall.CALL_EVENT_TYPE.name] = adminLevel;
|
||||
newContent.events[ElementCall.MEMBER_EVENT_TYPE.name] = adminLevel;
|
||||
}
|
||||
|
||||
room.client.sendStateEvent(room.roomId, EventType.RoomPowerLevels, {
|
||||
events: events,
|
||||
...content,
|
||||
});
|
||||
room.client.sendStateEvent(room.roomId, EventType.RoomPowerLevels, newContent);
|
||||
},
|
||||
[room.client, room.roomId, content, events, isPublic],
|
||||
[room.client, room.roomId, content, isPublic],
|
||||
);
|
||||
|
||||
const brand = SdkConfig.get("element_call").brand ?? DEFAULTS.element_call.brand;
|
||||
|
||||
@@ -27,7 +27,7 @@ type Props = {
|
||||
const MATCH_SYSTEM_THEME_ID = "MATCH_SYSTEM_THEME_ID";
|
||||
|
||||
const QuickThemeSwitcher: React.FC<Props> = ({ requestClose }) => {
|
||||
const orderedThemes = useMemo(getOrderedThemes, []);
|
||||
const orderedThemes = useMemo(() => getOrderedThemes(), []);
|
||||
|
||||
const themeState = useTheme();
|
||||
const nonHighContrast = findNonHighContrastTheme(themeState.theme);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { ClientEvent, MatrixClient, MatrixEventEvent, Room } from "matrix-js-sdk/src/matrix";
|
||||
import { throttle } from "lodash";
|
||||
|
||||
@@ -42,14 +42,12 @@ export function useUnreadThreadRooms(forceComputation: boolean): Result {
|
||||
setResult(computeUnreadThreadRooms(mxClient, msc3946ProcessDynamicPredecessor, settingTACOnlyNotifs));
|
||||
}, [mxClient, msc3946ProcessDynamicPredecessor, settingTACOnlyNotifs]);
|
||||
|
||||
// The exhautive deps lint rule can't compute dependencies here since it's not a plain inline func.
|
||||
// We make this as simple as possible so its only dep is doUpdate itself.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const scheduleUpdate = useCallback(
|
||||
throttle(doUpdate, MIN_UPDATE_INTERVAL_MS, {
|
||||
leading: false,
|
||||
trailing: true,
|
||||
}),
|
||||
const scheduleUpdate = useMemo(
|
||||
() =>
|
||||
throttle(doUpdate, MIN_UPDATE_INTERVAL_MS, {
|
||||
leading: false,
|
||||
trailing: true,
|
||||
}),
|
||||
[doUpdate],
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user