Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit b2fa2cf

Browse files
t3chguyAmy Walker
authored andcommitted
Remove all usages of UNSAFE_* React methods (#9583)
1 parent 6ab965c commit b2fa2cf

33 files changed

+582
-410
lines changed

src/components/structures/InteractiveAuth.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,7 @@ export default class InteractiveAuthComponent extends React.Component<IProps, IS
133133
}
134134
}
135135

136-
// TODO: [REACT-WARNING] Replace component with real class, use constructor for refs
137-
UNSAFE_componentWillMount() { // eslint-disable-line @typescript-eslint/naming-convention, camelcase
136+
public componentDidMount() {
138137
this.authLogic.attemptAuth().then((result) => {
139138
const extra = {
140139
emailSid: this.authLogic.getEmailSid(),

src/components/structures/MatrixChat.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -403,12 +403,17 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
403403
this.setState({ pendingInitialSync: false });
404404
}
405405

406-
// TODO: [REACT-WARNING] Replace with appropriate lifecycle stage
407-
// eslint-disable-next-line
408-
UNSAFE_componentWillUpdate(props, state) {
409-
if (this.shouldTrackPageChange(this.state, state)) {
406+
public setState<K extends keyof IState>(
407+
state: ((
408+
prevState: Readonly<IState>,
409+
props: Readonly<IProps>,
410+
) => (Pick<IState, K> | IState | null)) | (Pick<IState, K> | IState | null),
411+
callback?: () => void,
412+
): void {
413+
if (this.shouldTrackPageChange(this.state, { ...this.state, ...state })) {
410414
this.startPageChangeTimer();
411415
}
416+
super.setState<K>(state, callback);
412417
}
413418

414419
public componentDidMount(): void {

src/components/structures/TimelinePanel.tsx

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -299,22 +299,17 @@ class TimelinePanel extends React.Component<IProps, IState> {
299299
cli.on(ClientEvent.Sync, this.onSync);
300300
}
301301

302-
// TODO: [REACT-WARNING] Move into constructor
303-
// eslint-disable-next-line
304-
UNSAFE_componentWillMount() {
302+
public componentDidMount() {
305303
if (this.props.manageReadReceipts) {
306304
this.updateReadReceiptOnUserActivity();
307305
}
308306
if (this.props.manageReadMarkers) {
309307
this.updateReadMarkerOnUserActivity();
310308
}
311-
312309
this.initTimeline(this.props);
313310
}
314311

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

@@ -334,10 +329,9 @@ class TimelinePanel extends React.Component<IProps, IState> {
334329
const differentHighlightedEventId = newProps.highlightedEventId != this.props.highlightedEventId;
335330
const differentAvoidJump = newProps.eventScrollIntoView && !this.props.eventScrollIntoView;
336331
if (differentEventId || differentHighlightedEventId || differentAvoidJump) {
337-
logger.log("TimelinePanel switching to " +
338-
"eventId " + newProps.eventId + " (was " + this.props.eventId + "), " +
339-
"scrollIntoView: " + newProps.eventScrollIntoView + " (was " + this.props.eventScrollIntoView + ")");
340-
return this.initTimeline(newProps);
332+
logger.log(`TimelinePanel switching to eventId ${newProps.eventId} (was ${this.props.eventId}), ` +
333+
`scrollIntoView: ${newProps.eventScrollIntoView} (was ${this.props.eventScrollIntoView})`);
334+
this.initTimeline(newProps);
341335
}
342336
}
343337

src/components/structures/auth/ForgotPassword.tsx

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -113,17 +113,16 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
113113
this.checkServerCapabilities(this.props.serverConfig);
114114
}
115115

116-
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
117-
// eslint-disable-next-line
118-
public UNSAFE_componentWillReceiveProps(newProps: IProps): void {
119-
if (newProps.serverConfig.hsUrl === this.props.serverConfig.hsUrl &&
120-
newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return;
121-
122-
// Do a liveliness check on the new URLs
123-
this.checkServerLiveliness(newProps.serverConfig);
124-
125-
// Do capabilities check on new URLs
126-
this.checkServerCapabilities(newProps.serverConfig);
116+
public componentDidUpdate(prevProps: Readonly<IProps>) {
117+
if (prevProps.serverConfig.hsUrl !== this.props.serverConfig.hsUrl ||
118+
prevProps.serverConfig.isUrl !== this.props.serverConfig.isUrl
119+
) {
120+
// Do a liveliness check on the new URLs
121+
this.checkServerLiveliness(this.props.serverConfig);
122+
123+
// Do capabilities check on new URLs
124+
this.checkServerCapabilities(this.props.serverConfig);
125+
}
127126
}
128127

129128
private async checkServerLiveliness(serverConfig): Promise<void> {

src/components/structures/auth/Login.tsx

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -144,24 +144,21 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
144144
};
145145
}
146146

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

153151
componentWillUnmount() {
154152
this.unmounted = true;
155153
}
156154

157-
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
158-
// eslint-disable-next-line
159-
UNSAFE_componentWillReceiveProps(newProps) {
160-
if (newProps.serverConfig.hsUrl === this.props.serverConfig.hsUrl &&
161-
newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return;
162-
163-
// Ensure that we end up actually logging in to the right place
164-
this.initLoginLogic(newProps.serverConfig);
155+
public componentDidUpdate(prevProps) {
156+
if (prevProps.serverConfig.hsUrl !== this.props.serverConfig.hsUrl ||
157+
prevProps.serverConfig.isUrl !== this.props.serverConfig.isUrl
158+
) {
159+
// Ensure that we end up actually logging in to the right place
160+
this.initLoginLogic(this.props.serverConfig);
161+
}
165162
}
166163

167164
isBusy = () => this.state.busy || this.props.busy;
@@ -369,7 +366,8 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
369366
let isDefaultServer = false;
370367
if (this.props.serverConfig.isDefault
371368
&& hsUrl === this.props.serverConfig.hsUrl
372-
&& isUrl === this.props.serverConfig.isUrl) {
369+
&& isUrl === this.props.serverConfig.isUrl
370+
) {
373371
isDefaultServer = true;
374372
}
375373

src/components/structures/auth/Registration.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -165,13 +165,13 @@ export default class Registration extends React.Component<IProps, IState> {
165165
return "";
166166
}
167167
};
168-
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
169-
// eslint-disable-next-line
170-
UNSAFE_componentWillReceiveProps(newProps) {
171-
if (newProps.serverConfig.hsUrl === this.props.serverConfig.hsUrl &&
172-
newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return;
173168

174-
this.replaceClient(newProps.serverConfig);
169+
public componentDidUpdate(prevProps) {
170+
if (prevProps.serverConfig.hsUrl !== this.props.serverConfig.hsUrl ||
171+
prevProps.serverConfig.isUrl !== this.props.serverConfig.isUrl
172+
) {
173+
this.replaceClient(this.props.serverConfig);
174+
}
175175
}
176176

177177
private async replaceClient(serverConfig: ValidatedServerConfig) {

src/components/views/avatars/MemberAvatar.tsx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,21 @@ export default function MemberAvatar({
4949
height,
5050
resizeMethod = 'crop',
5151
viewUserOnClick,
52+
forceHistorical,
53+
fallbackUserId,
54+
hideTitle,
55+
member: propsMember,
5256
...props
5357
}: IProps) {
5458
const card = useContext(CardContext);
5559

5660
const member = useRoomMemberProfile({
57-
userId: props.member?.userId,
58-
member: props.member,
59-
forceHistorical: props.forceHistorical,
61+
userId: propsMember?.userId,
62+
member: propsMember,
63+
forceHistorical: forceHistorical,
6064
});
6165

62-
const name = member?.name ?? props.fallbackUserId;
66+
const name = member?.name ?? fallbackUserId;
6367
let title: string | undefined = props.title;
6468
let imageUrl: string | undefined;
6569
if (member?.name) {
@@ -74,7 +78,7 @@ export default function MemberAvatar({
7478
if (!title) {
7579
title = UserIdentifierCustomisations.getDisplayUserIdentifier(
7680
member?.userId ?? "", { roomId: member?.roomId ?? "" },
77-
) ?? props.fallbackUserId;
81+
) ?? fallbackUserId;
7882
}
7983
}
8084

@@ -84,13 +88,13 @@ export default function MemberAvatar({
8488
height={height}
8589
resizeMethod={resizeMethod}
8690
name={name ?? ""}
87-
title={props.hideTitle ? undefined : title}
88-
idName={member?.userId ?? props.fallbackUserId}
91+
title={hideTitle ? undefined : title}
92+
idName={member?.userId ?? fallbackUserId}
8993
url={imageUrl}
9094
onClick={viewUserOnClick ? () => {
9195
dis.dispatch({
9296
action: Action.ViewUser,
93-
member: props.member,
97+
member: propsMember,
9498
push: card.isCard,
9599
});
96100
} : props.onClick}

src/components/views/elements/AppTile.tsx

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ interface IState {
9999
isUserProfileReady: boolean;
100100
error: Error;
101101
menuDisplayed: boolean;
102-
widgetPageTitle: string;
103102
requiresClient: boolean;
104103
}
105104

@@ -229,7 +228,6 @@ export default class AppTile extends React.Component<IProps, IState> {
229228
isUserProfileReady: OwnProfileStore.instance.isProfileInfoFetched,
230229
error: null,
231230
menuDisplayed: false,
232-
widgetPageTitle: this.props.widgetPageTitle,
233231
requiresClient: this.determineInitialRequiresClientState(),
234232
};
235233
}
@@ -351,21 +349,13 @@ export default class AppTile extends React.Component<IProps, IState> {
351349
}
352350
};
353351

354-
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
355-
// eslint-disable-next-line @typescript-eslint/naming-convention
356-
public UNSAFE_componentWillReceiveProps(nextProps: IProps): void { // eslint-disable-line camelcase
357-
if (nextProps.app.url !== this.props.app.url) {
358-
this.getNewState(nextProps);
352+
public componentDidUpdate(prevProps: IProps): void {
353+
if (prevProps.app.url !== this.props.app.url) {
354+
this.getNewState(this.props);
359355
if (this.state.hasPermissionToLoad) {
360-
this.resetWidget(nextProps);
356+
this.resetWidget(this.props);
361357
}
362358
}
363-
364-
if (nextProps.widgetPageTitle !== this.props.widgetPageTitle) {
365-
this.setState({
366-
widgetPageTitle: nextProps.widgetPageTitle,
367-
});
368-
}
369359
}
370360

371361
/**
@@ -474,8 +464,8 @@ export default class AppTile extends React.Component<IProps, IState> {
474464
const name = this.formatAppTileName();
475465
const titleSpacer = <span>&nbsp;-&nbsp;</span>;
476466
let title = '';
477-
if (this.state.widgetPageTitle && this.state.widgetPageTitle !== this.formatAppTileName()) {
478-
title = this.state.widgetPageTitle;
467+
if (this.props.widgetPageTitle && this.props.widgetPageTitle !== this.formatAppTileName()) {
468+
title = this.props.widgetPageTitle;
479469
}
480470

481471
return (

src/components/views/elements/Dropdown.tsx

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import AccessibleButton, { ButtonEvent } from './AccessibleButton';
2222
import { _t } from '../../../languageHandler';
2323
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
2424
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
25+
import { objectHasDiff } from "../../../utils/objects";
2526

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

139-
componentWillUnmount() {
140-
document.removeEventListener('click', this.onDocumentClick, false);
140+
public componentDidUpdate(prevProps: Readonly<DropdownProps>) {
141+
if (objectHasDiff(this.props, prevProps) && this.props.children?.length) {
142+
this.reindexChildren(this.props.children);
143+
const firstChild = this.props.children[0];
144+
this.setState({
145+
highlightedOption: String(firstChild?.key) ?? null,
146+
});
147+
}
141148
}
142149

143-
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
144-
UNSAFE_componentWillReceiveProps(nextProps) { // eslint-disable-line
145-
if (!nextProps.children || nextProps.children.length === 0) {
146-
return;
147-
}
148-
this.reindexChildren(nextProps.children);
149-
const firstChild = nextProps.children[0];
150-
this.setState({
151-
highlightedOption: firstChild ? firstChild.key : null,
152-
});
150+
componentWillUnmount() {
151+
document.removeEventListener('click', this.onDocumentClick, false);
153152
}
154153

155154
private reindexChildren(children: ReactElement[]): void {

src/components/views/elements/EditableText.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,9 @@ export default class EditableText extends React.Component<IProps, IState> {
7070
};
7171
}
7272

73-
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
74-
// eslint-disable-next-line @typescript-eslint/naming-convention, camelcase
75-
public UNSAFE_componentWillReceiveProps(nextProps: IProps): void {
76-
if (nextProps.initialValue !== this.props.initialValue) {
77-
this.value = nextProps.initialValue;
73+
public componentDidUpdate(prevProps: Readonly<IProps>): void {
74+
if (prevProps.initialValue !== this.props.initialValue) {
75+
this.value = this.props.initialValue;
7876
if (this.editableDiv.current) {
7977
this.showPlaceholder(!this.value);
8078
}

src/components/views/elements/Pill.tsx

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import { Action } from "../../../dispatcher/actions";
2929
import Tooltip, { Alignment } from './Tooltip';
3030
import RoomAvatar from '../avatars/RoomAvatar';
3131
import MemberAvatar from '../avatars/MemberAvatar';
32+
import { objectHasDiff } from "../../../utils/objects";
3233

3334
export enum PillType {
3435
UserMention = 'TYPE_USER_MENTION',
@@ -86,19 +87,17 @@ export default class Pill extends React.Component<IProps, IState> {
8687
};
8788
}
8889

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

95-
if (nextProps.url) {
96-
if (nextProps.inMessage) {
97-
const parts = parsePermalink(nextProps.url);
94+
if (this.props.url) {
95+
if (this.props.inMessage) {
96+
const parts = parsePermalink(this.props.url);
9897
resourceId = parts.primaryEntityId; // The room/user ID
9998
prefix = parts.sigil; // The first character of prefix
10099
} else {
101-
resourceId = getPrimaryPermalinkEntity(nextProps.url);
100+
resourceId = getPrimaryPermalinkEntity(this.props.url);
102101
prefix = resourceId ? resourceId[0] : undefined;
103102
}
104103
}
@@ -109,15 +108,15 @@ export default class Pill extends React.Component<IProps, IState> {
109108
'!': PillType.RoomMention,
110109
}[prefix];
111110

112-
let member;
113-
let room;
111+
let member: RoomMember;
112+
let room: Room;
114113
switch (pillType) {
115114
case PillType.AtRoomMention: {
116-
room = nextProps.room;
115+
room = this.props.room;
117116
}
118117
break;
119118
case PillType.UserMention: {
120-
const localMember = nextProps.room ? nextProps.room.getMember(resourceId) : undefined;
119+
const localMember = this.props.room?.getMember(resourceId);
121120
member = localMember;
122121
if (!localMember) {
123122
member = new RoomMember(null, resourceId);
@@ -146,9 +145,13 @@ export default class Pill extends React.Component<IProps, IState> {
146145
public componentDidMount(): void {
147146
this.unmounted = false;
148147
this.matrixClient = MatrixClientPeg.get();
148+
this.load();
149+
}
149150

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

154157
public componentWillUnmount(): void {

0 commit comments

Comments
 (0)