Skip to content

Commit

Permalink
Remove all usages of UNSAFE_* React methods (#9583)
Browse files Browse the repository at this point in the history
  • Loading branch information
t3chguy committed Nov 18, 2022
1 parent 38dbe8e commit 590b845
Show file tree
Hide file tree
Showing 33 changed files with 582 additions and 410 deletions.
3 changes: 1 addition & 2 deletions src/components/structures/InteractiveAuth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,7 @@ export default class InteractiveAuthComponent extends React.Component<IProps, IS
}
}

// TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
UNSAFE_componentWillMount() { // eslint-disable-line @typescript-eslint/naming-convention, camelcase
public componentDidMount() {
this.authLogic.attemptAuth().then((result) => {
const extra = {
emailSid: this.authLogic.getEmailSid(),
Expand Down
13 changes: 9 additions & 4 deletions src/components/structures/MatrixChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -403,12 +403,17 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
this.setState({ pendingInitialSync: false });
}

// TODO: [REACT-WARNING] Replace with appropriate lifecycle stage
// eslint-disable-next-line
UNSAFE_componentWillUpdate(props, state) {
if (this.shouldTrackPageChange(this.state, state)) {
public setState<K extends keyof IState>(
state: ((
prevState: Readonly<IState>,
props: Readonly<IProps>,
) => (Pick<IState, K> | IState | null)) | (Pick<IState, K> | IState | null),
callback?: () => void,
): void {
if (this.shouldTrackPageChange(this.state, { ...this.state, ...state })) {
this.startPageChangeTimer();
}
super.setState<K>(state, callback);
}

public componentDidMount(): void {
Expand Down
16 changes: 5 additions & 11 deletions src/components/structures/TimelinePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -299,22 +299,17 @@ class TimelinePanel extends React.Component<IProps, IState> {
cli.on(ClientEvent.Sync, this.onSync);
}

// TODO: [REACT-WARNING] Move into constructor
// eslint-disable-next-line
UNSAFE_componentWillMount() {
public componentDidMount() {
if (this.props.manageReadReceipts) {
this.updateReadReceiptOnUserActivity();
}
if (this.props.manageReadMarkers) {
this.updateReadMarkerOnUserActivity();
}

this.initTimeline(this.props);
}

// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
// eslint-disable-next-line
UNSAFE_componentWillReceiveProps(newProps) {
public componentDidUpdate(newProps) {
if (newProps.timelineSet !== this.props.timelineSet) {
// throw new Error("changing timelineSet on a TimelinePanel is not supported");

Expand All @@ -334,10 +329,9 @@ class TimelinePanel extends React.Component<IProps, IState> {
const differentHighlightedEventId = newProps.highlightedEventId != this.props.highlightedEventId;
const differentAvoidJump = newProps.eventScrollIntoView && !this.props.eventScrollIntoView;
if (differentEventId || differentHighlightedEventId || differentAvoidJump) {
logger.log("TimelinePanel switching to " +
"eventId " + newProps.eventId + " (was " + this.props.eventId + "), " +
"scrollIntoView: " + newProps.eventScrollIntoView + " (was " + this.props.eventScrollIntoView + ")");
return this.initTimeline(newProps);
logger.log(`TimelinePanel switching to eventId ${newProps.eventId} (was ${this.props.eventId}), ` +
`scrollIntoView: ${newProps.eventScrollIntoView} (was ${this.props.eventScrollIntoView})`);
this.initTimeline(newProps);
}
}

Expand Down
21 changes: 10 additions & 11 deletions src/components/structures/auth/ForgotPassword.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,17 +113,16 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
this.checkServerCapabilities(this.props.serverConfig);
}

// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
// eslint-disable-next-line
public UNSAFE_componentWillReceiveProps(newProps: IProps): void {
if (newProps.serverConfig.hsUrl === this.props.serverConfig.hsUrl &&
newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return;

// Do a liveliness check on the new URLs
this.checkServerLiveliness(newProps.serverConfig);

// Do capabilities check on new URLs
this.checkServerCapabilities(newProps.serverConfig);
public componentDidUpdate(prevProps: Readonly<IProps>) {
if (prevProps.serverConfig.hsUrl !== this.props.serverConfig.hsUrl ||
prevProps.serverConfig.isUrl !== this.props.serverConfig.isUrl
) {
// Do a liveliness check on the new URLs
this.checkServerLiveliness(this.props.serverConfig);

// Do capabilities check on new URLs
this.checkServerCapabilities(this.props.serverConfig);
}
}

private async checkServerLiveliness(serverConfig): Promise<void> {
Expand Down
22 changes: 10 additions & 12 deletions src/components/structures/auth/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,24 +144,21 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
};
}

// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
// eslint-disable-next-line
UNSAFE_componentWillMount() {
public componentDidMount() {
this.initLoginLogic(this.props.serverConfig);
}

componentWillUnmount() {
this.unmounted = true;
}

// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
// eslint-disable-next-line
UNSAFE_componentWillReceiveProps(newProps) {
if (newProps.serverConfig.hsUrl === this.props.serverConfig.hsUrl &&
newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return;

// Ensure that we end up actually logging in to the right place
this.initLoginLogic(newProps.serverConfig);
public componentDidUpdate(prevProps) {
if (prevProps.serverConfig.hsUrl !== this.props.serverConfig.hsUrl ||
prevProps.serverConfig.isUrl !== this.props.serverConfig.isUrl
) {
// Ensure that we end up actually logging in to the right place
this.initLoginLogic(this.props.serverConfig);
}
}

isBusy = () => this.state.busy || this.props.busy;
Expand Down Expand Up @@ -369,7 +366,8 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
let isDefaultServer = false;
if (this.props.serverConfig.isDefault
&& hsUrl === this.props.serverConfig.hsUrl
&& isUrl === this.props.serverConfig.isUrl) {
&& isUrl === this.props.serverConfig.isUrl
) {
isDefaultServer = true;
}

Expand Down
12 changes: 6 additions & 6 deletions src/components/structures/auth/Registration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,13 +165,13 @@ export default class Registration extends React.Component<IProps, IState> {
return "";
}
};
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
// eslint-disable-next-line
UNSAFE_componentWillReceiveProps(newProps) {
if (newProps.serverConfig.hsUrl === this.props.serverConfig.hsUrl &&
newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return;

this.replaceClient(newProps.serverConfig);
public componentDidUpdate(prevProps) {
if (prevProps.serverConfig.hsUrl !== this.props.serverConfig.hsUrl ||
prevProps.serverConfig.isUrl !== this.props.serverConfig.isUrl
) {
this.replaceClient(this.props.serverConfig);
}
}

private async replaceClient(serverConfig: ValidatedServerConfig) {
Expand Down
20 changes: 12 additions & 8 deletions src/components/views/avatars/MemberAvatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,21 @@ export default function MemberAvatar({
height,
resizeMethod = 'crop',
viewUserOnClick,
forceHistorical,
fallbackUserId,
hideTitle,
member: propsMember,
...props
}: IProps) {
const card = useContext(CardContext);

const member = useRoomMemberProfile({
userId: props.member?.userId,
member: props.member,
forceHistorical: props.forceHistorical,
userId: propsMember?.userId,
member: propsMember,
forceHistorical: forceHistorical,
});

const name = member?.name ?? props.fallbackUserId;
const name = member?.name ?? fallbackUserId;
let title: string | undefined = props.title;
let imageUrl: string | undefined;
if (member?.name) {
Expand All @@ -74,7 +78,7 @@ export default function MemberAvatar({
if (!title) {
title = UserIdentifierCustomisations.getDisplayUserIdentifier(
member?.userId ?? "", { roomId: member?.roomId ?? "" },
) ?? props.fallbackUserId;
) ?? fallbackUserId;
}
}

Expand All @@ -84,13 +88,13 @@ export default function MemberAvatar({
height={height}
resizeMethod={resizeMethod}
name={name ?? ""}
title={props.hideTitle ? undefined : title}
idName={member?.userId ?? props.fallbackUserId}
title={hideTitle ? undefined : title}
idName={member?.userId ?? fallbackUserId}
url={imageUrl}
onClick={viewUserOnClick ? () => {
dis.dispatch({
action: Action.ViewUser,
member: props.member,
member: propsMember,
push: card.isCard,
});
} : props.onClick}
Expand Down
22 changes: 6 additions & 16 deletions src/components/views/elements/AppTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ interface IState {
isUserProfileReady: boolean;
error: Error;
menuDisplayed: boolean;
widgetPageTitle: string;
requiresClient: boolean;
}

Expand Down Expand Up @@ -229,7 +228,6 @@ export default class AppTile extends React.Component<IProps, IState> {
isUserProfileReady: OwnProfileStore.instance.isProfileInfoFetched,
error: null,
menuDisplayed: false,
widgetPageTitle: this.props.widgetPageTitle,
requiresClient: this.determineInitialRequiresClientState(),
};
}
Expand Down Expand Up @@ -351,21 +349,13 @@ export default class AppTile extends React.Component<IProps, IState> {
}
};

// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
// eslint-disable-next-line @typescript-eslint/naming-convention
public UNSAFE_componentWillReceiveProps(nextProps: IProps): void { // eslint-disable-line camelcase
if (nextProps.app.url !== this.props.app.url) {
this.getNewState(nextProps);
public componentDidUpdate(prevProps: IProps): void {
if (prevProps.app.url !== this.props.app.url) {
this.getNewState(this.props);
if (this.state.hasPermissionToLoad) {
this.resetWidget(nextProps);
this.resetWidget(this.props);
}
}

if (nextProps.widgetPageTitle !== this.props.widgetPageTitle) {
this.setState({
widgetPageTitle: nextProps.widgetPageTitle,
});
}
}

/**
Expand Down Expand Up @@ -474,8 +464,8 @@ export default class AppTile extends React.Component<IProps, IState> {
const name = this.formatAppTileName();
const titleSpacer = <span>&nbsp;-&nbsp;</span>;
let title = '';
if (this.state.widgetPageTitle && this.state.widgetPageTitle !== this.formatAppTileName()) {
title = this.state.widgetPageTitle;
if (this.props.widgetPageTitle && this.props.widgetPageTitle !== this.formatAppTileName()) {
title = this.props.widgetPageTitle;
}

return (
Expand Down
23 changes: 11 additions & 12 deletions src/components/views/elements/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import AccessibleButton, { ButtonEvent } from './AccessibleButton';
import { _t } from '../../../languageHandler';
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
import { objectHasDiff } from "../../../utils/objects";

interface IMenuOptionProps {
children: ReactElement;
Expand Down Expand Up @@ -136,20 +137,18 @@ export default class Dropdown extends React.Component<DropdownProps, IState> {
document.addEventListener('click', this.onDocumentClick, false);
}

componentWillUnmount() {
document.removeEventListener('click', this.onDocumentClick, false);
public componentDidUpdate(prevProps: Readonly<DropdownProps>) {
if (objectHasDiff(this.props, prevProps) && this.props.children?.length) {
this.reindexChildren(this.props.children);
const firstChild = this.props.children[0];
this.setState({
highlightedOption: String(firstChild?.key) ?? null,
});
}
}

// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
UNSAFE_componentWillReceiveProps(nextProps) { // eslint-disable-line
if (!nextProps.children || nextProps.children.length === 0) {
return;
}
this.reindexChildren(nextProps.children);
const firstChild = nextProps.children[0];
this.setState({
highlightedOption: firstChild ? firstChild.key : null,
});
componentWillUnmount() {
document.removeEventListener('click', this.onDocumentClick, false);
}

private reindexChildren(children: ReactElement[]): void {
Expand Down
8 changes: 3 additions & 5 deletions src/components/views/elements/EditableText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,9 @@ export default class EditableText extends React.Component<IProps, IState> {
};
}

// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
// eslint-disable-next-line @typescript-eslint/naming-convention, camelcase
public UNSAFE_componentWillReceiveProps(nextProps: IProps): void {
if (nextProps.initialValue !== this.props.initialValue) {
this.value = nextProps.initialValue;
public componentDidUpdate(prevProps: Readonly<IProps>): void {
if (prevProps.initialValue !== this.props.initialValue) {
this.value = this.props.initialValue;
if (this.editableDiv.current) {
this.showPlaceholder(!this.value);
}
Expand Down
33 changes: 18 additions & 15 deletions src/components/views/elements/Pill.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { Action } from "../../../dispatcher/actions";
import Tooltip, { Alignment } from './Tooltip';
import RoomAvatar from '../avatars/RoomAvatar';
import MemberAvatar from '../avatars/MemberAvatar';
import { objectHasDiff } from "../../../utils/objects";

export enum PillType {
UserMention = 'TYPE_USER_MENTION',
Expand Down Expand Up @@ -86,19 +87,17 @@ export default class Pill extends React.Component<IProps, IState> {
};
}

// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
// eslint-disable-next-line camelcase, @typescript-eslint/naming-convention
public async UNSAFE_componentWillReceiveProps(nextProps: IProps): Promise<void> {
let resourceId;
let prefix;
private load(): void {
let resourceId: string;
let prefix: string;

if (nextProps.url) {
if (nextProps.inMessage) {
const parts = parsePermalink(nextProps.url);
if (this.props.url) {
if (this.props.inMessage) {
const parts = parsePermalink(this.props.url);
resourceId = parts.primaryEntityId; // The room/user ID
prefix = parts.sigil; // The first character of prefix
} else {
resourceId = getPrimaryPermalinkEntity(nextProps.url);
resourceId = getPrimaryPermalinkEntity(this.props.url);
prefix = resourceId ? resourceId[0] : undefined;
}
}
Expand All @@ -109,15 +108,15 @@ export default class Pill extends React.Component<IProps, IState> {
'!': PillType.RoomMention,
}[prefix];

let member;
let room;
let member: RoomMember;
let room: Room;
switch (pillType) {
case PillType.AtRoomMention: {
room = nextProps.room;
room = this.props.room;
}
break;
case PillType.UserMention: {
const localMember = nextProps.room ? nextProps.room.getMember(resourceId) : undefined;
const localMember = this.props.room?.getMember(resourceId);
member = localMember;
if (!localMember) {
member = new RoomMember(null, resourceId);
Expand Down Expand Up @@ -146,9 +145,13 @@ export default class Pill extends React.Component<IProps, IState> {
public componentDidMount(): void {
this.unmounted = false;
this.matrixClient = MatrixClientPeg.get();
this.load();
}

// eslint-disable-next-line new-cap
this.UNSAFE_componentWillReceiveProps(this.props); // HACK: We shouldn't be calling lifecycle functions ourselves.
public componentDidUpdate(prevProps: Readonly<IProps>) {
if (objectHasDiff(this.props, prevProps)) {
this.load();
}
}

public componentWillUnmount(): void {
Expand Down

0 comments on commit 590b845

Please sign in to comment.