diff --git a/.eslintignore.errorfiles b/.eslintignore.errorfiles index d9177bebb5..ea66720529 100644 --- a/.eslintignore.errorfiles +++ b/.eslintignore.errorfiles @@ -4,7 +4,6 @@ src/Markdown.js src/NodeAnimator.js src/components/structures/RoomDirectory.js src/components/views/rooms/MemberList.js -src/ratelimitedfunc.js src/utils/DMRoomMap.js src/utils/MultiInviter.js test/components/structures/MessagePanel-test.js diff --git a/src/components/structures/RightPanel.tsx b/src/components/structures/RightPanel.tsx index c608f0eee9..338bfc06ab 100644 --- a/src/components/structures/RightPanel.tsx +++ b/src/components/structures/RightPanel.tsx @@ -23,7 +23,6 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; import dis from '../../dispatcher/dispatcher'; -import RateLimitedFunc from '../../ratelimitedfunc'; import GroupStore from '../../stores/GroupStore'; import { RIGHT_PANEL_PHASES_NO_ARGS, @@ -48,6 +47,7 @@ import FilePanel from "./FilePanel"; import NotificationPanel from "./NotificationPanel"; import ResizeNotifier from "../../utils/ResizeNotifier"; import PinnedMessagesCard from "../views/right_panel/PinnedMessagesCard"; +import { DebouncedFunc, throttle } from 'lodash'; interface IProps { room?: Room; // if showing panels for a given room, this is set @@ -73,7 +73,7 @@ interface IState { export default class RightPanel extends React.Component { static contextType = MatrixClientContext; - private readonly delayedUpdate: RateLimitedFunc; + private readonly delayedUpdate: DebouncedFunc<() => void>; private dispatcherRef: string; constructor(props, context) { @@ -85,9 +85,9 @@ export default class RightPanel extends React.Component { member: this.getUserForPanel(), }; - this.delayedUpdate = new RateLimitedFunc(() => { + this.delayedUpdate = throttle(() => { this.forceUpdate(); - }, 500); + }, 500, { leading: true, trailing: true }); } // Helper function to split out the logic for getPhaseFromProps() and the constructor diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index 81000a87a6..d08eaa2ecd 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -37,7 +37,6 @@ import Modal from '../../Modal'; import * as sdk from '../../index'; import CallHandler, { PlaceCallType } from '../../CallHandler'; import dis from '../../dispatcher/dispatcher'; -import rateLimitedFunc from '../../ratelimitedfunc'; import * as Rooms from '../../Rooms'; import eventSearch, { searchPagination } from '../../Searching'; import MainSplit from './MainSplit'; @@ -82,6 +81,7 @@ import { IOpts } from "../../createRoom"; import { replaceableComponent } from "../../utils/replaceableComponent"; import UIStore from "../../stores/UIStore"; import EditorStateTransfer from "../../utils/EditorStateTransfer"; +import { throttle } from "lodash"; const DEBUG = false; let debuglog = function(msg: string) {}; @@ -675,8 +675,8 @@ export default class RoomView extends React.Component { ); } - // cancel any pending calls to the rate_limited_funcs - this.updateRoomMembers.cancelPendingCall(); + // cancel any pending calls to the throttled updated + this.updateRoomMembers.cancel(); for (const watcher of this.settingWatchers) { SettingsStore.unwatchSetting(watcher); @@ -1092,7 +1092,7 @@ export default class RoomView extends React.Component { return; } - this.updateRoomMembers(member); + this.updateRoomMembers(); }; private onMyMembership = (room: Room, membership: string, oldMembership: string) => { @@ -1114,10 +1114,10 @@ export default class RoomView extends React.Component { } // rate limited because a power level change will emit an event for every member in the room. - private updateRoomMembers = rateLimitedFunc(() => { + private updateRoomMembers = throttle(() => { this.updateDMState(); this.updateE2EStatus(this.state.room); - }, 500); + }, 500, { leading: true, trailing: true }); private checkDesktopNotifications() { const memberCount = this.state.room.getJoinedMemberCount() + this.state.room.getInvitedMemberCount(); diff --git a/src/components/views/rooms/AuxPanel.tsx b/src/components/views/rooms/AuxPanel.tsx index 1c817140fa..99286dfa07 100644 --- a/src/components/views/rooms/AuxPanel.tsx +++ b/src/components/views/rooms/AuxPanel.tsx @@ -21,7 +21,6 @@ import { Room } from 'matrix-js-sdk/src/models/room'; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import AppsDrawer from './AppsDrawer'; -import RateLimitedFunc from '../../../ratelimitedfunc'; import SettingsStore from "../../../settings/SettingsStore"; import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; import { UIFeature } from "../../../settings/UIFeature"; @@ -29,6 +28,7 @@ import ResizeNotifier from "../../../utils/ResizeNotifier"; import CallViewForRoom from '../voip/CallViewForRoom'; import { objectHasDiff } from "../../../utils/objects"; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { throttle } from 'lodash'; interface IProps { // js-sdk room object @@ -99,9 +99,9 @@ export default class AuxPanel extends React.Component { } } - private rateLimitedUpdate = new RateLimitedFunc(() => { + private rateLimitedUpdate = throttle(() => { this.setState({ counters: this.computeCounters() }); - }, 500); + }, 500, { leading: true, trailing: true }); private computeCounters() { const counters = []; diff --git a/src/components/views/rooms/MemberList.tsx b/src/components/views/rooms/MemberList.tsx index 68f87580df..f4df70c7ee 100644 --- a/src/components/views/rooms/MemberList.tsx +++ b/src/components/views/rooms/MemberList.tsx @@ -22,7 +22,6 @@ import { _t } from '../../../languageHandler'; import SdkConfig from '../../../SdkConfig'; import dis from '../../../dispatcher/dispatcher'; import { isValid3pidInvite } from "../../../RoomInvite"; -import rateLimitedFunction from "../../../ratelimitedfunc"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { CommunityPrototypeStore } from "../../../stores/CommunityPrototypeStore"; import BaseCard from "../right_panel/BaseCard"; @@ -43,6 +42,7 @@ import AccessibleButton from '../elements/AccessibleButton'; import EntityTile from "./EntityTile"; import MemberTile from "./MemberTile"; import BaseAvatar from '../avatars/BaseAvatar'; +import { throttle } from 'lodash'; const INITIAL_LOAD_NUM_MEMBERS = 30; const INITIAL_LOAD_NUM_INVITED = 5; @@ -133,7 +133,7 @@ export default class MemberList extends React.Component { } // cancel any pending calls to the rate_limited_funcs - this.updateList.cancelPendingCall(); + this.updateList.cancel(); } /** @@ -237,9 +237,9 @@ export default class MemberList extends React.Component { if (this.canInvite !== this.state.canInvite) this.setState({ canInvite: this.canInvite }); }; - private updateList = rateLimitedFunction(() => { + private updateList = throttle(() => { this.updateListNow(); - }, 500); + }, 500, { leading: true, trailing: true }); private updateListNow(): void { const members = this.roomMembers(); diff --git a/src/components/views/rooms/RoomHeader.js b/src/components/views/rooms/RoomHeader.js index 886317f2bf..b05b709e36 100644 --- a/src/components/views/rooms/RoomHeader.js +++ b/src/components/views/rooms/RoomHeader.js @@ -20,7 +20,6 @@ import PropTypes from 'prop-types'; import classNames from 'classnames'; import { _t } from '../../../languageHandler'; import { MatrixClientPeg } from '../../../MatrixClientPeg'; -import RateLimitedFunc from '../../../ratelimitedfunc'; import SettingsStore from "../../../settings/SettingsStore"; import RoomHeaderButtons from '../right_panel/RoomHeaderButtons'; @@ -31,6 +30,7 @@ import RoomTopic from "../elements/RoomTopic"; import RoomName from "../elements/RoomName"; import { PlaceCallType } from "../../../CallHandler"; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import { throttle } from 'lodash'; @replaceableComponent("views.rooms.RoomHeader") export default class RoomHeader extends React.Component { @@ -73,10 +73,9 @@ export default class RoomHeader extends React.Component { this._rateLimitedUpdate(); }; - _rateLimitedUpdate = new RateLimitedFunc(function() { - /* eslint-disable @babel/no-invalid-this */ + _rateLimitedUpdate = throttle(() => { this.forceUpdate(); - }, 500); + }, 500, { leading: true, trailing: true }); render() { let searchStatus = null; diff --git a/src/components/views/rooms/SendMessageComposer.tsx b/src/components/views/rooms/SendMessageComposer.tsx index f088ec0c8e..ec190c829a 100644 --- a/src/components/views/rooms/SendMessageComposer.tsx +++ b/src/components/views/rooms/SendMessageComposer.tsx @@ -39,7 +39,6 @@ import Modal from '../../../Modal'; import { _t, _td } from '../../../languageHandler'; import ContentMessages from '../../../ContentMessages'; import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import RateLimitedFunc from '../../../ratelimitedfunc'; import { Action } from "../../../dispatcher/actions"; import { containsEmoji } from "../../../effects/utils"; import { CHAT_EFFECTS } from '../../../effects'; @@ -53,6 +52,7 @@ import { Room } from 'matrix-js-sdk/src/models/room'; import ErrorDialog from "../dialogs/ErrorDialog"; import QuestionDialog from "../dialogs/QuestionDialog"; import { ActionPayload } from "../../../dispatcher/payloads"; +import { DebouncedFunc, throttle } from 'lodash'; function addReplyToMessageContent( content: IContent, @@ -138,7 +138,7 @@ export default class SendMessageComposer extends React.Component { static contextType = MatrixClientContext; context!: React.ContextType; - private readonly prepareToEncrypt?: RateLimitedFunc; + private readonly prepareToEncrypt?: DebouncedFunc<() => void>; private readonly editorRef = createRef(); private model: EditorModel = null; private currentlyComposedEditorState: SerializedPart[] = null; @@ -149,9 +149,9 @@ export default class SendMessageComposer extends React.Component { super(props); this.context = context; // otherwise React will only set it prior to render due to type def above if (this.context.isCryptoEnabled() && this.context.isRoomEncrypted(this.props.room.roomId)) { - this.prepareToEncrypt = new RateLimitedFunc(() => { + this.prepareToEncrypt = throttle(() => { this.context.prepareToEncrypt(this.props.room); - }, 60000); + }, 60000, { leading: true, trailing: false }); } window.addEventListener("beforeunload", this.saveStoredEditorState); diff --git a/src/ratelimitedfunc.js b/src/ratelimitedfunc.js deleted file mode 100644 index 3df3db615e..0000000000 --- a/src/ratelimitedfunc.js +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright 2016 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -/** - * 'debounces' a function to only execute every n milliseconds. - * Useful when react-sdk gets many, many events but only wants - * to update the interface once for all of them. - * - * Note that the function must not take arguments, since the args - * could be different for each invocation of the function. - * - * The returned function has a 'cancelPendingCall' property which can be called - * on unmount or similar to cancel any pending update. - */ - -import {throttle} from "lodash"; - -export default function ratelimitedfunc(fn, time) { - const throttledFn = throttle(fn, time, { - leading: true, - trailing: true, - }); - const _bind = throttledFn.bind; - throttledFn.bind = function() { - const boundFn = _bind.apply(throttledFn, arguments); - boundFn.cancelPendingCall = throttledFn.cancelPendingCall; - return boundFn; - }; - - throttledFn.cancelPendingCall = function() { - throttledFn.cancel(); - }; - return throttledFn; -}