From 4c55f3c5b536786d5b088b1c378f1eed8a4309cd Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sun, 8 Dec 2019 12:12:06 +0000 Subject: [PATCH 1/4] Remove unused refs Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/GroupView.js | 36 ++++++++++---------- src/components/structures/RoomDirectory.js | 2 +- src/components/structures/RoomView.js | 4 +-- src/components/views/messages/MAudioBody.js | 2 +- src/components/views/messages/MFileBody.js | 2 +- src/components/views/messages/MImageBody.js | 4 +-- src/components/views/messages/MVideoBody.js | 6 ++-- src/components/views/rooms/AuxPanel.js | 5 +-- src/components/views/rooms/RoomDetailList.js | 2 +- src/components/views/rooms/RoomNameEditor.js | 16 ++++----- 10 files changed, 40 insertions(+), 39 deletions(-) diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index a0aa36803f..d52599abe9 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -1214,25 +1214,25 @@ export default createReactClass({ const EditableText = sdk.getComponent("elements.EditableText"); - nameNode = ; + nameNode = ; - shortDescNode = ; + shortDescNode = ; } else { const onGroupHeaderItemClick = this.state.isUserMember ? this._onEditClick : null; const groupAvatarUrl = summary.profile ? summary.profile.avatar_url : null; diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js index efca8d12a8..c8863773f4 100644 --- a/src/components/structures/RoomDirectory.js +++ b/src/components/structures/RoomDirectory.js @@ -572,7 +572,7 @@ module.exports = createReactClass({ if (rows.length === 0 && !this.state.loading) { scrollpanel_content = { _t('No rooms to show') }; } else { - scrollpanel_content = + scrollpanel_content =
{ rows } diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 5cc1e2b765..679b385c71 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1719,7 +1719,7 @@ module.exports = createReactClass({ aux = ; } else if (this.state.searching) { hideCancel = true; // has own cancel - aux = ; + aux = ; } else if (showRoomUpgradeBar) { aux = ; hideCancel = true; @@ -1775,7 +1775,7 @@ module.exports = createReactClass({ } const auxPanel = ( - + { _t("Error decrypting audio") } diff --git a/src/components/views/messages/MFileBody.js b/src/components/views/messages/MFileBody.js index 7f4d76747a..d231a86f36 100644 --- a/src/components/views/messages/MFileBody.js +++ b/src/components/views/messages/MFileBody.js @@ -325,7 +325,7 @@ module.exports = createReactClass({ }; return ( - +
{ _t("Decrypt %(text)s", { text: text }) } diff --git a/src/components/views/messages/MImageBody.js b/src/components/views/messages/MImageBody.js index b12957a7df..3c20aab529 100644 --- a/src/components/views/messages/MImageBody.js +++ b/src/components/views/messages/MImageBody.js @@ -459,7 +459,7 @@ export default class MImageBody extends React.Component { if (this.state.error !== null) { return ( - + { _t("Error decrypting image") } @@ -477,7 +477,7 @@ export default class MImageBody extends React.Component { const thumbnail = this._messageContent(contentUrl, thumbUrl, content); const fileBody = this.getFileBody(); - return + return { thumbnail } { fileBody } ; diff --git a/src/components/views/messages/MVideoBody.js b/src/components/views/messages/MVideoBody.js index 44954344ff..8366d0dd01 100644 --- a/src/components/views/messages/MVideoBody.js +++ b/src/components/views/messages/MVideoBody.js @@ -132,7 +132,7 @@ module.exports = createReactClass({ if (this.state.error !== null) { return ( - + { _t("Error decrypting video") } @@ -144,8 +144,8 @@ module.exports = createReactClass({ // The attachment is decrypted in componentDidMount. // For now add an img tag with a spinner. return ( - -
+ +
{content.body}
diff --git a/src/components/views/rooms/AuxPanel.js b/src/components/views/rooms/AuxPanel.js index ffb5d9272d..a83160ddbf 100644 --- a/src/components/views/rooms/AuxPanel.js +++ b/src/components/views/rooms/AuxPanel.js @@ -188,14 +188,15 @@ module.exports = createReactClass({ } const callView = ( - ); - const appsDrawer = { _t('No rooms to show') }; } else { - rooms =
+ rooms =
{ this.getRows() } diff --git a/src/components/views/rooms/RoomNameEditor.js b/src/components/views/rooms/RoomNameEditor.js index 5bdf719e97..375a4b42b1 100644 --- a/src/components/views/rooms/RoomNameEditor.js +++ b/src/components/views/rooms/RoomNameEditor.js @@ -65,14 +65,14 @@ module.exports = createReactClass({ return (
- +
); }, From d22985f12e222f997ef9c118f072d7bbe936194d Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sun, 8 Dec 2019 12:16:17 +0000 Subject: [PATCH 2/4] Migrate string refs over to createRef Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- code_style.md | 8 +- .../views/dialogs/ExportE2eKeysDialog.js | 13 ++-- .../views/dialogs/ImportE2eKeysDialog.js | 23 ++++-- src/components/structures/InteractiveAuth.js | 15 ++-- src/components/structures/LoggedInView.js | 14 ++-- src/components/structures/MessagePanel.js | 75 ++++++++++--------- src/components/structures/RoomSubList.js | 32 ++++---- src/components/structures/RoomView.js | 62 ++++++++------- src/components/structures/ScrollPanel.js | 28 +++---- src/components/structures/SearchBox.js | 22 +++--- src/components/structures/TimelinePanel.js | 61 ++++++++------- src/components/views/auth/CaptchaForm.js | 10 ++- .../auth/InteractiveAuthEntryComponents.js | 10 ++- .../views/dialogs/AddressPickerDialog.js | 22 +++--- src/components/views/dialogs/SetMxIdDialog.js | 17 +++-- src/components/views/dialogs/ShareDialog.js | 8 +- .../views/dialogs/TextInputDialog.js | 18 ++++- src/components/views/elements/AppTile.js | 16 ++-- src/components/views/elements/EditableText.js | 21 +++--- src/components/views/elements/UserSelector.js | 14 ++-- .../views/messages/EditHistoryMessage.js | 12 +-- src/components/views/messages/MFileBody.js | 26 ++++--- src/components/views/messages/MImageBody.js | 12 +-- src/components/views/messages/MessageEvent.js | 11 ++- src/components/views/messages/TextualBody.js | 22 +++--- .../room_settings/RoomProfileSettings.js | 8 +- src/components/views/rooms/EventTile.js | 21 +++--- .../views/rooms/LinkPreviewWidget.js | 14 ++-- src/components/views/rooms/MessageComposer.js | 10 ++- src/components/views/rooms/RoomBreadcrumbs.js | 10 ++- src/components/views/rooms/RoomDetailRow.js | 12 ++- src/components/views/rooms/RoomHeader.js | 12 ++- src/components/views/rooms/SearchBar.js | 16 ++-- .../views/rooms/SlateMessageComposer.js | 10 +-- .../views/settings/ProfileSettings.js | 8 +- .../tabs/room/NotificationSettingsTab.js | 8 +- src/components/views/voip/CallView.js | 12 ++- src/components/views/voip/VideoFeed.js | 12 ++- src/components/views/voip/VideoView.js | 15 ++-- 39 files changed, 438 insertions(+), 302 deletions(-) diff --git a/code_style.md b/code_style.md index 4b2338064c..3ad0d38873 100644 --- a/code_style.md +++ b/code_style.md @@ -174,12 +174,6 @@ React // Best, if onFooClick would do anything other than directly calling doStuff ``` - Not doing so is acceptable in a single case: in function-refs: - - ```jsx - this.component = self}> - ``` - - Prefer classes that extend `React.Component` (or `React.PureComponent`) instead of `React.createClass` - You can avoid the need to bind handler functions by using [property initializers](https://reactjs.org/docs/react-component.html#constructor): @@ -208,3 +202,5 @@ React ``` - Think about whether your component really needs state: are you duplicating information in component state that could be derived from the model? + +- Avoid things marked as Legacy or Deprecated in React 16 (e.g string refs and legacy contexts) diff --git a/src/async-components/views/dialogs/ExportE2eKeysDialog.js b/src/async-components/views/dialogs/ExportE2eKeysDialog.js index 0fd412935a..ba2e985889 100644 --- a/src/async-components/views/dialogs/ExportE2eKeysDialog.js +++ b/src/async-components/views/dialogs/ExportE2eKeysDialog.js @@ -15,7 +15,7 @@ limitations under the License. */ import FileSaver from 'file-saver'; -import React from 'react'; +import React, {createRef} from 'react'; import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; import { _t } from '../../../languageHandler'; @@ -44,6 +44,9 @@ export default createReactClass({ componentWillMount: function() { this._unmounted = false; + + this._passphrase1 = createRef(); + this._passphrase2 = createRef(); }, componentWillUnmount: function() { @@ -53,8 +56,8 @@ export default createReactClass({ _onPassphraseFormSubmit: function(ev) { ev.preventDefault(); - const passphrase = this.refs.passphrase1.value; - if (passphrase !== this.refs.passphrase2.value) { + const passphrase = this._passphrase1.current.value; + if (passphrase !== this._passphrase2.current.value) { this.setState({errStr: _t('Passphrases must match')}); return false; } @@ -148,7 +151,7 @@ export default createReactClass({
- @@ -161,7 +164,7 @@ export default createReactClass({
- diff --git a/src/async-components/views/dialogs/ImportE2eKeysDialog.js b/src/async-components/views/dialogs/ImportE2eKeysDialog.js index 17f3bba117..de9e819f5a 100644 --- a/src/async-components/views/dialogs/ImportE2eKeysDialog.js +++ b/src/async-components/views/dialogs/ImportE2eKeysDialog.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; +import React, {createRef} from 'react'; import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; @@ -56,6 +56,9 @@ export default createReactClass({ componentWillMount: function() { this._unmounted = false; + + this._file = createRef(); + this._passphrase = createRef(); }, componentWillUnmount: function() { @@ -63,15 +66,15 @@ export default createReactClass({ }, _onFormChange: function(ev) { - const files = this.refs.file.files || []; + const files = this._file.current.files || []; this.setState({ - enableSubmit: (this.refs.passphrase.value !== "" && files.length > 0), + enableSubmit: (this._passphrase.current.value !== "" && files.length > 0), }); }, _onFormSubmit: function(ev) { ev.preventDefault(); - this._startImport(this.refs.file.files[0], this.refs.passphrase.value); + this._startImport(this._file.current.files[0], this._passphrase.current.value); return false; }, @@ -146,7 +149,10 @@ export default createReactClass({
- @@ -159,8 +165,11 @@ export default createReactClass({
-
diff --git a/src/components/structures/InteractiveAuth.js b/src/components/structures/InteractiveAuth.js index e1b02f653b..1981310a2f 100644 --- a/src/components/structures/InteractiveAuth.js +++ b/src/components/structures/InteractiveAuth.js @@ -18,7 +18,7 @@ limitations under the License. import Matrix from 'matrix-js-sdk'; const InteractiveAuth = Matrix.InteractiveAuth; -import React from 'react'; +import React, {createRef} from 'react'; import createReactClass from 'create-react-class'; import PropTypes from 'prop-types'; @@ -129,6 +129,8 @@ export default createReactClass({ this._authLogic.poll(); }, 2000); } + + this._stageComponent = createRef(); }, componentWillUnmount: function() { @@ -153,8 +155,8 @@ export default createReactClass({ }, tryContinue: function() { - if (this.refs.stageComponent && this.refs.stageComponent.tryContinue) { - this.refs.stageComponent.tryContinue(); + if (this._stageComponent.current && this._stageComponent.current.tryContinue) { + this._stageComponent.current.tryContinue(); } }, @@ -192,8 +194,8 @@ export default createReactClass({ }, _setFocus: function() { - if (this.refs.stageComponent && this.refs.stageComponent.focus) { - this.refs.stageComponent.focus(); + if (this._stageComponent.current && this._stageComponent.current.focus) { + this._stageComponent.current.focus(); } }, @@ -214,7 +216,8 @@ export default createReactClass({ const StageComponent = getEntryComponentForLoginType(stage); return ( - { hr } @@ -829,14 +831,14 @@ export default class MessagePanel extends React.Component { // once dynamic content in the events load, make the scrollPanel check the // scroll offsets. _onHeightChanged = () => { - const scrollPanel = this.refs.scrollPanel; + const scrollPanel = this._scrollPanel.current; if (scrollPanel) { scrollPanel.checkScroll(); } }; _onTypingShown = () => { - const scrollPanel = this.refs.scrollPanel; + const scrollPanel = this._scrollPanel.current; // this will make the timeline grow, so checkScroll scrollPanel.checkScroll(); if (scrollPanel && scrollPanel.getScrollState().stuckAtBottom) { @@ -845,7 +847,7 @@ export default class MessagePanel extends React.Component { }; _onTypingHidden = () => { - const scrollPanel = this.refs.scrollPanel; + const scrollPanel = this._scrollPanel.current; if (scrollPanel) { // as hiding the typing notifications doesn't // update the scrollPanel, we tell it to apply @@ -858,11 +860,11 @@ export default class MessagePanel extends React.Component { }; updateTimelineMinHeight() { - const scrollPanel = this.refs.scrollPanel; + const scrollPanel = this._scrollPanel.current; if (scrollPanel) { const isAtBottom = scrollPanel.isAtBottom(); - const whoIsTyping = this.refs.whoIsTyping; + const whoIsTyping = this._whoIsTyping.current; const isTypingVisible = whoIsTyping && whoIsTyping.isVisible(); // when messages get added to the timeline, // but somebody else is still typing, @@ -875,7 +877,7 @@ export default class MessagePanel extends React.Component { } onTimelineReset() { - const scrollPanel = this.refs.scrollPanel; + const scrollPanel = this._scrollPanel.current; if (scrollPanel) { scrollPanel.clearPreventShrinking(); } @@ -909,19 +911,22 @@ export default class MessagePanel extends React.Component { room={this.props.room} onShown={this._onTypingShown} onHidden={this._onTypingHidden} - ref="whoIsTyping" /> + ref={this._whoIsTyping} /> ); } return ( - + { topSpinner } { this._getEventTiles() } { whoIsTyping } diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js index 921680b678..fe43e60405 100644 --- a/src/components/structures/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -82,8 +82,14 @@ const RoomSubList = createReactClass({ }; }, - componentDidMount: function() { + UNSAFE_componentWillMount: function() { + this._header = createRef(); + this._subList = createRef(); + this._scroller = createRef(); this._headerButton = createRef(); + }, + + componentDidMount: function() { this.dispatcherRef = dis.register(this.onAction); }, @@ -103,7 +109,7 @@ const RoomSubList = createReactClass({ // The header is collapsible if it is hidden or not stuck // The dataset elements are added in the RoomList _initAndPositionStickyHeaders method isCollapsibleOnClick: function() { - const stuck = this.refs.header.dataset.stuck; + const stuck = this._header.current.dataset.stuck; if (!this.props.forceExpand && (this.state.hidden || stuck === undefined || stuck === "none")) { return true; } else { @@ -135,7 +141,7 @@ const RoomSubList = createReactClass({ }); } else { // The header is stuck, so the click is to be interpreted as a scroll to the header - this.props.onHeaderClick(this.state.hidden, this.refs.header.dataset.originalPosition); + this.props.onHeaderClick(this.state.hidden, this._header.current.dataset.originalPosition); } }, @@ -159,7 +165,7 @@ const RoomSubList = createReactClass({ this.onClick(); } else if (!this.props.forceExpand) { // sublist is expanded, go to first room - const element = this.refs.subList && this.refs.subList.querySelector(".mx_RoomTile"); + const element = this._subList.current && this._subList.current.querySelector(".mx_RoomTile"); if (element) { element.focus(); } @@ -328,7 +334,7 @@ const RoomSubList = createReactClass({ } return ( -
+
+ this.makeRoomTile(r)); const tiles = roomTiles.concat(this.props.extraTiles); content = ( - + { tiles } ); @@ -418,7 +424,7 @@ const RoomSubList = createReactClass({ return (
{ - const scrollPanel = this.refs.searchResultsPanel; + const scrollPanel = this._searchResultsPanel.current; if (scrollPanel) { scrollPanel.checkScroll(); } @@ -1370,28 +1373,28 @@ module.exports = createReactClass({ // jump down to the bottom of this room, where new events are arriving jumpToLiveTimeline: function() { - this.refs.messagePanel.jumpToLiveTimeline(); + this._messagePanel.jumpToLiveTimeline(); dis.dispatch({action: 'focus_composer'}); }, // jump up to wherever our read marker is jumpToReadMarker: function() { - this.refs.messagePanel.jumpToReadMarker(); + this._messagePanel.jumpToReadMarker(); }, // update the read marker to match the read-receipt forgetReadMarker: function(ev) { ev.stopPropagation(); - this.refs.messagePanel.forgetReadMarker(); + this._messagePanel.forgetReadMarker(); }, // decide whether or not the top 'unread messages' bar should be shown _updateTopUnreadMessagesBar: function() { - if (!this.refs.messagePanel) { + if (!this._messagePanel) { return; } - const showBar = this.refs.messagePanel.canJumpToReadMarker(); + const showBar = this._messagePanel.canJumpToReadMarker(); if (this.state.showTopUnreadMessagesBar != showBar) { this.setState({showTopUnreadMessagesBar: showBar}); } @@ -1401,7 +1404,7 @@ module.exports = createReactClass({ // restored when we switch back to it. // _getScrollState: function() { - const messagePanel = this.refs.messagePanel; + const messagePanel = this._messagePanel; if (!messagePanel) return null; // if we're following the live timeline, we want to return null; that @@ -1506,10 +1509,10 @@ module.exports = createReactClass({ */ handleScrollKey: function(ev) { let panel; - if (this.refs.searchResultsPanel) { - panel = this.refs.searchResultsPanel; - } else if (this.refs.messagePanel) { - panel = this.refs.messagePanel; + if (this._searchResultsPanel.current) { + panel = this._searchResultsPanel.current; + } else if (this._messagePanel) { + panel = this._messagePanel; } if (panel) { @@ -1530,7 +1533,7 @@ module.exports = createReactClass({ // this has to be a proper method rather than an unnamed function, // otherwise react calls it with null on each update. _gatherTimelinePanelRef: function(r) { - this.refs.messagePanel = r; + this._messagePanel = r; if (r) { console.log("updateTint from RoomView._gatherTimelinePanelRef"); this.updateTint(); @@ -1875,7 +1878,7 @@ module.exports = createReactClass({ searchResultsPanel = (
); } else { searchResultsPanel = ( - +
- = 0; --i) { @@ -756,7 +758,7 @@ module.exports = createReactClass({ }, _getMessagesHeight() { - const itemlist = this.refs.itemlist; + const itemlist = this._itemlist.current; const lastNode = itemlist.lastElementChild; const lastNodeBottom = lastNode ? lastNode.offsetTop + lastNode.clientHeight : 0; const firstNodeTop = itemlist.firstElementChild ? itemlist.firstElementChild.offsetTop : 0; @@ -765,7 +767,7 @@ module.exports = createReactClass({ }, _topFromBottom(node) { - return this.refs.itemlist.clientHeight - node.offsetTop; + return this._itemlist.current.clientHeight - node.offsetTop; }, /* get the DOM node which has the scrollTop property we care about for our @@ -797,7 +799,7 @@ module.exports = createReactClass({ the same minimum bottom offset, effectively preventing the timeline to shrink. */ preventShrinking: function() { - const messageList = this.refs.itemlist; + const messageList = this._itemlist.current; const tiles = messageList && messageList.children; if (!messageList) { return; @@ -824,7 +826,7 @@ module.exports = createReactClass({ /** Clear shrinking prevention. Used internally, and when the timeline is reloaded. */ clearPreventShrinking: function() { - const messageList = this.refs.itemlist; + const messageList = this._itemlist.current; const balanceElement = messageList && messageList.parentElement; if (balanceElement) balanceElement.style.paddingBottom = null; this.preventShrinkingState = null; @@ -843,7 +845,7 @@ module.exports = createReactClass({ if (this.preventShrinkingState) { const sn = this._getScrollNode(); const scrollState = this.scrollState; - const messageList = this.refs.itemlist; + const messageList = this._itemlist.current; const {offsetNode, offsetFromBottom} = this.preventShrinkingState; // element used to set paddingBottom to balance the typing notifs disappearing const balanceElement = messageList.parentElement; @@ -879,7 +881,7 @@ module.exports = createReactClass({ onScroll={this.onScroll} className={`mx_ScrollPanel ${this.props.className}`} style={this.props.style}>
-
    +
      { this.props.children }
diff --git a/src/components/structures/SearchBox.js b/src/components/structures/SearchBox.js index 21613733db..0aa2e15f4c 100644 --- a/src/components/structures/SearchBox.js +++ b/src/components/structures/SearchBox.js @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; +import React, {createRef} from 'react'; import createReactClass from 'create-react-class'; import PropTypes from 'prop-types'; import { KeyCode } from '../../Keyboard'; @@ -53,6 +53,10 @@ module.exports = createReactClass({ }; }, + UNSAFE_componentWillMount: function() { + this._search = createRef(); + }, + componentDidMount: function() { this.dispatcherRef = dis.register(this.onAction); }, @@ -66,26 +70,26 @@ module.exports = createReactClass({ switch (payload.action) { case 'view_room': - if (this.refs.search && payload.clear_search) { + if (this._search.current && payload.clear_search) { this._clearSearch(); } break; case 'focus_room_filter': - if (this.refs.search) { - this.refs.search.focus(); + if (this._search.current) { + this._search.current.focus(); } break; } }, onChange: function() { - if (!this.refs.search) return; - this.setState({ searchTerm: this.refs.search.value }); + if (!this._search.current) return; + this.setState({ searchTerm: this._search.current.value }); this.onSearch(); }, onSearch: throttle(function() { - this.props.onSearch(this.refs.search.value); + this.props.onSearch(this._search.current.value); }, 200, {trailing: true, leading: true}), _onKeyDown: function(ev) { @@ -113,7 +117,7 @@ module.exports = createReactClass({ }, _clearSearch: function(source) { - this.refs.search.value = ""; + this._search.current.value = ""; this.onChange(); if (this.props.onCleared) { this.props.onCleared(source); @@ -146,7 +150,7 @@ module.exports = createReactClass({ { - if (payload.event && this.refs.messagePanel) { - this.refs.messagePanel.scrollToEventIfNeeded( + if (payload.event && this._messagePanel.current) { + this._messagePanel.current.scrollToEventIfNeeded( payload.event.getId(), ); } @@ -442,9 +444,9 @@ const TimelinePanel = createReactClass({ // updates from pagination will happen when the paginate completes. if (toStartOfTimeline || !data || !data.liveEvent) return; - if (!this.refs.messagePanel) return; + if (!this._messagePanel.current) return; - if (!this.refs.messagePanel.getScrollState().stuckAtBottom) { + if (!this._messagePanel.current.getScrollState().stuckAtBottom) { // we won't load this event now, because we don't want to push any // events off the other end of the timeline. But we need to note // that we can now paginate. @@ -499,7 +501,7 @@ const TimelinePanel = createReactClass({ } this.setState(updatedState, () => { - this.refs.messagePanel.updateTimelineMinHeight(); + this._messagePanel.current.updateTimelineMinHeight(); if (callRMUpdated) { this.props.onReadMarkerUpdated(); } @@ -510,13 +512,13 @@ const TimelinePanel = createReactClass({ onRoomTimelineReset: function(room, timelineSet) { if (timelineSet !== this.props.timelineSet) return; - if (this.refs.messagePanel && this.refs.messagePanel.isAtBottom()) { + if (this._messagePanel.current && this._messagePanel.current.isAtBottom()) { this._loadTimeline(); } }, canResetTimeline: function() { - return this.refs.messagePanel && this.refs.messagePanel.isAtBottom(); + return this._messagePanel.current && this._messagePanel.current.isAtBottom(); }, onRoomRedaction: function(ev, room) { @@ -629,7 +631,7 @@ const TimelinePanel = createReactClass({ sendReadReceipt: function() { if (SettingsStore.getValue("lowBandwidth")) return; - if (!this.refs.messagePanel) return; + if (!this._messagePanel.current) return; if (!this.props.manageReadReceipts) return; // This happens on user_activity_end which is delayed, and it's // very possible have logged out within that timeframe, so check @@ -815,8 +817,8 @@ const TimelinePanel = createReactClass({ if (this._timelineWindow.canPaginate(EventTimeline.FORWARDS)) { this._loadTimeline(); } else { - if (this.refs.messagePanel) { - this.refs.messagePanel.scrollToBottom(); + if (this._messagePanel.current) { + this._messagePanel.current.scrollToBottom(); } } }, @@ -826,7 +828,7 @@ const TimelinePanel = createReactClass({ */ jumpToReadMarker: function() { if (!this.props.manageReadMarkers) return; - if (!this.refs.messagePanel) return; + if (!this._messagePanel.current) return; if (!this.state.readMarkerEventId) return; // we may not have loaded the event corresponding to the read-marker @@ -835,11 +837,11 @@ const TimelinePanel = createReactClass({ // // a quick way to figure out if we've loaded the relevant event is // simply to check if the messagepanel knows where the read-marker is. - const ret = this.refs.messagePanel.getReadMarkerPosition(); + const ret = this._messagePanel.current.getReadMarkerPosition(); if (ret !== null) { // The messagepanel knows where the RM is, so we must have loaded // the relevant event. - this.refs.messagePanel.scrollToEvent(this.state.readMarkerEventId, + this._messagePanel.current.scrollToEvent(this.state.readMarkerEventId, 0, 1/3); return; } @@ -874,8 +876,8 @@ const TimelinePanel = createReactClass({ * at the end of the live timeline. */ isAtEndOfLiveTimeline: function() { - return this.refs.messagePanel - && this.refs.messagePanel.isAtBottom() + return this._messagePanel.current + && this._messagePanel.current.isAtBottom() && this._timelineWindow && !this._timelineWindow.canPaginate(EventTimeline.FORWARDS); }, @@ -887,8 +889,8 @@ const TimelinePanel = createReactClass({ * returns null if we are not mounted. */ getScrollState: function() { - if (!this.refs.messagePanel) { return null; } - return this.refs.messagePanel.getScrollState(); + if (!this._messagePanel.current) { return null; } + return this._messagePanel.current.getScrollState(); }, // returns one of: @@ -899,9 +901,9 @@ const TimelinePanel = createReactClass({ // +1: read marker is below the window getReadMarkerPosition: function() { if (!this.props.manageReadMarkers) return null; - if (!this.refs.messagePanel) return null; + if (!this._messagePanel.current) return null; - const ret = this.refs.messagePanel.getReadMarkerPosition(); + const ret = this._messagePanel.current.getReadMarkerPosition(); if (ret !== null) { return ret; } @@ -936,7 +938,7 @@ const TimelinePanel = createReactClass({ * We pass it down to the scroll panel. */ handleScrollKey: function(ev) { - if (!this.refs.messagePanel) { return; } + if (!this._messagePanel.current) { return; } // jump to the live timeline on ctrl-end, rather than the end of the // timeline window. @@ -944,7 +946,7 @@ const TimelinePanel = createReactClass({ ev.keyCode == KeyCode.END) { this.jumpToLiveTimeline(); } else { - this.refs.messagePanel.handleScrollKey(ev); + this._messagePanel.current.handleScrollKey(ev); } }, @@ -986,8 +988,8 @@ const TimelinePanel = createReactClass({ const onLoaded = () => { // clear the timeline min-height when // (re)loading the timeline - if (this.refs.messagePanel) { - this.refs.messagePanel.onTimelineReset(); + if (this._messagePanel.current) { + this._messagePanel.current.onTimelineReset(); } this._reloadEvents(); @@ -1002,7 +1004,7 @@ const TimelinePanel = createReactClass({ timelineLoading: false, }, () => { // initialise the scroll state of the message panel - if (!this.refs.messagePanel) { + if (!this._messagePanel.current) { // this shouldn't happen - we know we're mounted because // we're in a setState callback, and we know // timelineLoading is now false, so render() should have @@ -1012,10 +1014,10 @@ const TimelinePanel = createReactClass({ return; } if (eventId) { - this.refs.messagePanel.scrollToEvent(eventId, pixelOffset, + this._messagePanel.current.scrollToEvent(eventId, pixelOffset, offsetBase); } else { - this.refs.messagePanel.scrollToBottom(); + this._messagePanel.current.scrollToBottom(); } this.sendReadReceipt(); @@ -1134,7 +1136,7 @@ const TimelinePanel = createReactClass({ const ignoreOwn = opts.ignoreOwn || false; const allowPartial = opts.allowPartial || false; - const messagePanel = this.refs.messagePanel; + const messagePanel = this._messagePanel.current; if (messagePanel === undefined) return null; const EventTile = sdk.getComponent('rooms.EventTile'); @@ -1313,7 +1315,8 @@ const TimelinePanel = createReactClass({ ['PREPARED', 'CATCHUP'].includes(this.state.clientSyncState) ); return ( -

{_t( "This homeserver would like to make sure you are not a robot.", )}

-
+
{ error }
); diff --git a/src/components/views/auth/InteractiveAuthEntryComponents.js b/src/components/views/auth/InteractiveAuthEntryComponents.js index cc3f9f96c4..dd661291f3 100644 --- a/src/components/views/auth/InteractiveAuthEntryComponents.js +++ b/src/components/views/auth/InteractiveAuthEntryComponents.js @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; +import React, {createRef} from 'react'; import createReactClass from 'create-react-class'; import PropTypes from 'prop-types'; import url from 'url'; @@ -581,6 +581,8 @@ export const FallbackAuthEntry = createReactClass({ // the popup if we open it immediately. this._popupWindow = null; window.addEventListener("message", this._onReceiveMessage); + + this._fallbackButton = createRef(); }, componentWillUnmount: function() { @@ -591,8 +593,8 @@ export const FallbackAuthEntry = createReactClass({ }, focus: function() { - if (this.refs.fallbackButton) { - this.refs.fallbackButton.focus(); + if (this._fallbackButton.current) { + this._fallbackButton.current.focus(); } }, @@ -624,7 +626,7 @@ export const FallbackAuthEntry = createReactClass({ } return (
); diff --git a/src/components/views/dialogs/AddressPickerDialog.js b/src/components/views/dialogs/AddressPickerDialog.js index a40495893d..2be505a798 100644 --- a/src/components/views/dialogs/AddressPickerDialog.js +++ b/src/components/views/dialogs/AddressPickerDialog.js @@ -17,7 +17,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; +import React, {createRef} from 'react'; import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; @@ -106,10 +106,14 @@ module.exports = createReactClass({ }; }, + UNSAFE_componentWillMount: function() { + this._textinput = createRef(); + }, + componentDidMount: function() { if (this.props.focus) { // Set the cursor at the end of the text input - this.refs.textinput.value = this.props.value; + this._textinput.current.value = this.props.value; } }, @@ -126,8 +130,8 @@ module.exports = createReactClass({ let selectedList = this.state.selectedList.slice(); // Check the text input field to see if user has an unconverted address // If there is and it's valid add it to the local selectedList - if (this.refs.textinput.value !== '') { - selectedList = this._addAddressesToList([this.refs.textinput.value]); + if (this._textinput.current.value !== '') { + selectedList = this._addAddressesToList([this._textinput.current.value]); if (selectedList === null) return; } this.props.onFinished(true, selectedList); @@ -154,23 +158,23 @@ module.exports = createReactClass({ e.stopPropagation(); e.preventDefault(); if (this.addressSelector) this.addressSelector.chooseSelection(); - } else if (this.refs.textinput.value.length === 0 && this.state.selectedList.length && e.keyCode === 8) { // backspace + } else if (this._textinput.current.value.length === 0 && this.state.selectedList.length && e.keyCode === 8) { // backspace e.stopPropagation(); e.preventDefault(); this.onDismissed(this.state.selectedList.length - 1)(); } else if (e.keyCode === 13) { // enter e.stopPropagation(); e.preventDefault(); - if (this.refs.textinput.value === '') { + if (this._textinput.current.value === '') { // if there's nothing in the input box, submit the form this.onButtonClick(); } else { - this._addAddressesToList([this.refs.textinput.value]); + this._addAddressesToList([this._textinput.current.value]); } } else if (e.keyCode === 188 || e.keyCode === 9) { // comma or tab e.stopPropagation(); e.preventDefault(); - this._addAddressesToList([this.refs.textinput.value]); + this._addAddressesToList([this._textinput.current.value]); } }, @@ -647,7 +651,7 @@ module.exports = createReactClass({ onPaste={this._onPaste} rows="1" id="textinput" - ref="textinput" + ref={this._textinput} className="mx_AddressPickerDialog_input" onChange={this.onQueryChanged} placeholder={this.getPlaceholder()} diff --git a/src/components/views/dialogs/SetMxIdDialog.js b/src/components/views/dialogs/SetMxIdDialog.js index 598d0ce354..0294c1c700 100644 --- a/src/components/views/dialogs/SetMxIdDialog.js +++ b/src/components/views/dialogs/SetMxIdDialog.js @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; +import React, {createRef} from 'react'; import createReactClass from 'create-react-class'; import PropTypes from 'prop-types'; import sdk from '../../../index'; @@ -62,8 +62,13 @@ export default createReactClass({ }; }, + UNSAFE_componentWillMount: function() { + this._input_value = createRef(); + this._uiAuth = createRef(); + }, + componentDidMount: function() { - this.refs.input_value.select(); + this._input_value.current.select(); this._matrixClient = MatrixClientPeg.get(); }, @@ -102,8 +107,8 @@ export default createReactClass({ }, onSubmit: function(ev) { - if (this.refs.uiAuth) { - this.refs.uiAuth.tryContinue(); + if (this._uiAuth.current) { + this._uiAuth.current.tryContinue(); } this.setState({ doingUIAuth: true, @@ -215,7 +220,7 @@ export default createReactClass({ onAuthFinished={this._onUIAuthFinished} inputs={{}} poll={true} - ref="uiAuth" + ref={this._uiAuth} continueIsManaged={true} />; } @@ -257,7 +262,7 @@ export default createReactClass({ >
- diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index 55cb9a5487..9f75e5433b 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -64,6 +64,8 @@ export default class AppTile extends React.Component { this._onReloadWidgetClick = this._onReloadWidgetClick.bind(this); this._contextMenuButton = createRef(); + this._appFrame = createRef(); + this._menu_bar = createRef(); } /** @@ -337,14 +339,14 @@ export default class AppTile extends React.Component { // HACK: This is a really dirty way to ensure that Jitsi cleans up // its hold on the webcam. Without this, the widget holds a media // stream open, even after death. See https://github.com/vector-im/riot-web/issues/7351 - if (this.refs.appFrame) { + if (this._appFrame.current) { // In practice we could just do `+= ''` to trick the browser // into thinking the URL changed, however I can foresee this // being optimized out by a browser. Instead, we'll just point // the iframe at a page that is reasonably safe to use in the // event the iframe doesn't wink away. // This is relative to where the Riot instance is located. - this.refs.appFrame.src = 'about:blank'; + this._appFrame.current.src = 'about:blank'; } WidgetUtils.setRoomWidget( @@ -389,7 +391,7 @@ export default class AppTile extends React.Component { // FIXME: There's probably no reason to do this here: it should probably be done entirely // in ActiveWidgetStore. const widgetMessaging = new WidgetMessaging( - this.props.id, this.props.url, this.props.userWidget, this.refs.appFrame.contentWindow); + this.props.id, this.props.url, this.props.userWidget, this._appFrame.current.contentWindow); ActiveWidgetStore.setWidgetMessaging(this.props.id, widgetMessaging); widgetMessaging.getCapabilities().then((requestedCapabilities) => { console.log(`Widget ${this.props.id} requested capabilities: ` + requestedCapabilities); @@ -496,7 +498,7 @@ export default class AppTile extends React.Component { ev.preventDefault(); // Ignore clicks on menu bar children - if (ev.target !== this.refs.menu_bar) { + if (ev.target !== this._menu_bar.current) { return; } @@ -555,7 +557,7 @@ export default class AppTile extends React.Component { _onReloadWidgetClick() { // Reload iframe in this way to avoid cross-origin restrictions - this.refs.appFrame.src = this.refs.appFrame.src; + this._appFrame.current.src = this._appFrame.current.src; } _onContextMenuClick = () => { @@ -626,7 +628,7 @@ export default class AppTile extends React.Component { { this.state.loading && loadingElement }