Skip to content

Commit 139636c

Browse files
authored
useMemo with debounce (#1715)
* useMemo with debounce `debounce` requires memoization, otherwise every component re-render recreates the debouncing function. We change some existing, memoized instances of `debounce` using `useCallback` to use `useMemo` primarily to address (es)linting issues. Fixes: https://mattermost.atlassian.net/browse/MM-48509 * not.exists is safer than not.be.visible * simplify usePlaybooksCrud
1 parent 08df7b2 commit 139636c

File tree

11 files changed

+46
-29
lines changed

11 files changed

+46
-29
lines changed

tests-e2e/cypress/integration/playbooks/edit_spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,7 @@ describe('playbooks > edit', () => {
555555
.click({force: true});
556556

557557
// * Verify that the confirmation dialog is closed
558-
cy.get('#confirmModal').should('not.be.visible');
558+
cy.get('#confirmModal').should('not.exist');
559559

560560
cy.reload();
561561

@@ -612,7 +612,7 @@ describe('playbooks > edit', () => {
612612
.click({force: true});
613613

614614
// * Verify that confirmation dialog is closed
615-
cy.get('#confirmModal').should('not.be.visible');
615+
cy.get('#confirmModal').should('not.exist');
616616

617617
cy.reload();
618618

tests-e2e/cypress/integration/runs/rdp_main_retrospective_spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ describe('runs > run details page', () => {
247247
testRun = playbookRun;
248248
});
249249
});
250+
250251
beforeEach(() => {
251252
cy.visit(`/playbooks/runs/${testRun.id}`);
252253
});
@@ -297,8 +298,7 @@ describe('runs > run details page', () => {
297298
});
298299
});
299300

300-
// skipped flaky test: https://mattermost.atlassian.net/browse/MM-48509
301-
it.skip('auto save', () => {
301+
it('auto save', () => {
302302
getRetro().within(() => {
303303
// # Enter metric values
304304
cy.get('input[type=text]').eq(0).click();

webapp/src/components/backstage/playbook_runs/playbook_run/retrospective.tsx

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, {useRef, useState} from 'react';
1+
import React, {useMemo, useRef, useState} from 'react';
22
import styled from 'styled-components';
33
import {useIntl} from 'react-intl';
44
import debounce from 'debounce';
@@ -40,6 +40,19 @@ const Retrospective = ({
4040
const childRef = useRef<any>();
4141
const metricsAvailable = useAllowPlaybookAndRunMetrics();
4242

43+
const onMetricsChange = useMemo(
44+
() => debounce((metrics_data: RunMetricData[]) => {
45+
updateRetrospective(playbookRun.id, playbookRun.retrospective, metrics_data);
46+
}, DEBOUNCE_2_SECS),
47+
[playbookRun.id, playbookRun.retrospective],
48+
);
49+
const onReportChange = useMemo(
50+
() => debounce((retrospective: string) => {
51+
updateRetrospective(playbookRun.id, retrospective, playbookRun.metrics_data);
52+
}, DEBOUNCE_2_SECS),
53+
[playbookRun.id, playbookRun.metrics_data],
54+
);
55+
4356
if (!playbookRun.retrospective_enabled) {
4457
return null;
4558
}
@@ -113,13 +126,6 @@ const Retrospective = ({
113126
);
114127
};
115128

116-
const onMetricsChange = debounce((metrics_data: RunMetricData[]) => {
117-
updateRetrospective(playbookRun.id, playbookRun.retrospective, metrics_data);
118-
}, DEBOUNCE_2_SECS);
119-
const onReportChange = debounce((retrospective: string) => {
120-
updateRetrospective(playbookRun.id, retrospective, playbookRun.metrics_data);
121-
}, DEBOUNCE_2_SECS);
122-
123129
return (
124130
<Container
125131
id={id}

webapp/src/components/backstage/profile_autocomplete.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import React, {useMemo} from 'react';
22
import {useIntl} from 'react-intl';
33
import {debounce} from 'debounce';
44
import AsyncSelect from 'react-select/async';
@@ -119,7 +119,7 @@ const ProfileAutocomplete = (props: Props) => {
119119
);
120120
};
121121

122-
const debouncedSearchProfiles = debounce((term: string, callback: (options: OptionsType<UserProfile>) => void) => {
122+
const debouncedSearchProfiles = useMemo(() => debounce((term: string, callback: (options: OptionsType<UserProfile>) => void) => {
123123
let profiles;
124124
if (term.trim().length === 0) {
125125
profiles = props.getProfiles?.();
@@ -135,7 +135,7 @@ const ProfileAutocomplete = (props: Props) => {
135135
console.error('Error searching user profiles in custom attribute settings dropdown.');
136136
callback([]);
137137
});
138-
}, 150);
138+
}, 150), [props]);
139139

140140
const usersLoader = (term: string, callback: (options: OptionsType<UserProfile>) => void) => {
141141
try {

webapp/src/components/backstage/runs_list/filters.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
22
// See LICENSE.txt for license information.
33

4-
import React, {useState} from 'react';
4+
import React, {useMemo, useState} from 'react';
55
import debounce from 'debounce';
66
import {ControlProps, components} from 'react-select';
77
import styled from 'styled-components';
@@ -145,12 +145,17 @@ const Filters = ({fetchParams, setFetchParams, fixedPlaybook, fixedFinished}: Pr
145145
return playbooks ? playbooks.items : [] as Playbook[];
146146
}
147147

148+
const onSearch = useMemo(
149+
() => debounce(setSearchTerm, searchDebounceDelayMilliseconds),
150+
[setSearchTerm],
151+
);
152+
148153
return (
149154
<PlaybookRunListFilters>
150155
<SearchInput
151156
testId={'search-filter'}
152157
default={fetchParams.search_term}
153-
onSearch={debounce(setSearchTerm, searchDebounceDelayMilliseconds)}
158+
onSearch={onSearch}
154159
placeholder={formatMessage({defaultMessage: 'Search by run name'})}
155160
/>
156161
<CheckboxInput

webapp/src/components/datetime_input.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ const DateTimeInput = ({
101101
const datetimes = parseDateTimes(locale, query)?.map(({start}) => DateTime.fromJSDate(start.date()));
102102
const duration = parse(locale, query, Mode.DurationValue);
103103
setOptions(makeOptions(query, datetimes, duration ? [duration] : [], mode) || null);
104-
}, 150), [locale, setOptions, makeOptions]);
104+
}, 150), [locale, setOptions, makeOptions, mode]);
105105

106106
return (
107107
<StyledSelect

webapp/src/components/datetime_selector.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ export const DateTimeSelector = ({
121121
const duration = parse(locale, query, Mode.DurationValue);
122122

123123
setOptionsDateTime(makeOptions?.(query, datetimes, duration ? [duration] : [], mode) ?? suggestedOptions);
124-
}, 150), [makeOptions, suggestedOptions, mode]);
124+
}, 150), [locale, makeOptions, suggestedOptions, mode]);
125125

126126
const noDropdown = {DropdownIndicator: null, IndicatorSeparator: null};
127127
const components = props.customControl ? {

webapp/src/components/rhs/rhs_run_list.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
22
// See LICENSE.txt for license information.
33

4-
import React, {useState} from 'react';
4+
import React, {useMemo, useState} from 'react';
55
import {FormattedMessage, useIntl} from 'react-intl';
66
import {useDispatch, useSelector} from 'react-redux';
77
import styled from 'styled-components';
@@ -91,7 +91,7 @@ const RHSRunList = (props: Props) => {
9191
const currentTeamId = useSelector(getCurrentTeamId);
9292
const currentChannelId = useSelector(getCurrentChannelId);
9393
const [loadingMore, setLoadingMore] = useState(false);
94-
const debouncedSetLoadingMore = debounce(setLoadingMore, 100);
94+
const debouncedSetLoadingMore = useMemo(() => debounce(setLoadingMore, 100), [setLoadingMore]);
9595
const getMore = async () => {
9696
debouncedSetLoadingMore(true);
9797
await props.getMore();

webapp/src/components/widgets/text_with_tooltip.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React, {
22
ComponentProps,
33
useCallback,
44
useEffect,
5+
useMemo,
56
useRef,
67
useState,
78
} from 'react';
@@ -21,7 +22,7 @@ const TextWithTooltip = (props: Props) => {
2122
const ref = useRef<HTMLAnchorElement|null>(null);
2223
const [showTooltip, setShowTooltip] = useState(false);
2324

24-
const resizeListener = useCallback(debounce(() => {
25+
const resizeListener = useMemo(() => debounce(() => {
2526
if (ref?.current && ref?.current?.offsetWidth < ref?.current?.scrollWidth) {
2627
setShowTooltip(true);
2728
} else {

webapp/src/hooks/crud.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {useEffect, useState} from 'react';
1+
import {useEffect, useMemo, useState} from 'react';
22
import debounce from 'debounce';
33
import {useIntl} from 'react-intl';
44

@@ -155,11 +155,16 @@ export function usePlaybooksCrud(
155155
setParams({sort: colName, direction: 'desc'});
156156
};
157157

158-
const setSearchTerm = (term: string) => {
159-
setLoading(true);
160-
setParams({search_term: term, page: 0});
161-
};
162-
const setSearchTermDebounced = debounce(setSearchTerm, searchDebounceDelayMilliseconds);
158+
const setSearchTermDebounced = useMemo(
159+
() => debounce(
160+
(term: string) => {
161+
setLoading(true);
162+
setParams({search_term: term, page: 0});
163+
},
164+
searchDebounceDelayMilliseconds
165+
),
166+
[setLoading, setParams],
167+
);
163168

164169
const setWithArchived = (with_archived: boolean) => {
165170
setLoading(true);

webapp/src/hooks/general.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -667,7 +667,7 @@ export const useProxyState = <T>(
667667
setValue(prop);
668668
}, [prop]);
669669

670-
const onChangeDebounced = useCallback(debounce((v) => {
670+
const onChangeDebounced = useMemo(() => debounce((v) => {
671671
check.current = v; // send check
672672
onChange(v);
673673
}, wait), [wait, onChange]);

0 commit comments

Comments
 (0)