Skip to content

Commit d6b7ddb

Browse files
Scheduler - The number of dataCellRender function calls increases each time the parent component is re-rendered (#729) (#738)
T1097917 fix: In some cases (for example: setting more than one prop in one useCallback ) template component is removed before it's got on onRemove listener, therefore it's instance keeps in templatesStore. For fix it we subscribe on dxRemove event on container; Co-authored-by: volvl <[email protected]> Co-authored-by: volvl <[email protected]>
1 parent 7ed7710 commit d6b7ddb

File tree

2 files changed

+51
-4
lines changed

2 files changed

+51
-4
lines changed

packages/devextreme-react/src/core/__tests__/template.test.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,32 @@ function testTemplateOption(testedOption: string) {
335335
expect(templatesKeys[0]).not.toBe(templatesKeys[1]);
336336
});
337337

338+
it('removes previous template if its container was removed', () => {
339+
const ref = React.createRef() as React.RefObject<ComponentWithTemplates>;
340+
341+
const elementOptions: Record<string, any> = {};
342+
elementOptions[testedOption] = prepareTemplate((data: any) => (
343+
<div className="template">
344+
Template
345+
{data.text}
346+
</div>
347+
));
348+
render(
349+
<ComponentWithTemplates {...elementOptions} ref={ref} />,
350+
);
351+
352+
const componentInstance = ref.current as unknown as {
353+
_templatesStore: { _templates: Record<string, TemplateWrapperRenderer> } };
354+
355+
const container = document.createElement('div');
356+
renderItemTemplate({ text: 1 }, container);
357+
events.triggerHandler(container, 'dxremove');
358+
renderItemTemplate({ text: 1 }, document.createElement('div'));
359+
360+
const templatesKeys = Object.getOwnPropertyNames(componentInstance._templatesStore._templates);
361+
expect(templatesKeys.length).toBe(1);
362+
});
363+
338364
it('has templates with ids genetated with keyExpr', () => {
339365
const ref = React.createRef() as React.RefObject<ComponentWithTemplates>;
340366

packages/devextreme-react/src/core/dx-template.ts

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { DoubleKeyMap, generateID } from './helpers';
44
import { ITemplateArgs } from './template';
55
import { ITemplateWrapperProps, TemplateWrapper } from './template-wrapper';
66
import { TemplatesStore } from './templates-store';
7+
import {DX_REMOVE_EVENT} from "./component-base";
8+
import * as events from 'devextreme/events';
79

810
interface IDxTemplate {
911
render: (data: IDxTemplateData) => any;
@@ -35,6 +37,23 @@ function createDxTemplate(
3537

3638
let templateId: string;
3739

40+
const onRemoved = (): void => {
41+
templatesStore.setDeferredRemove(templateId, true);
42+
renderedTemplates.delete(key);
43+
};
44+
45+
const _subscribeOnContainerRemoval = (): void => {
46+
if (container.nodeType === Node.ELEMENT_NODE) {
47+
events.one(container, DX_REMOVE_EVENT, onRemoved);
48+
}
49+
}
50+
51+
const _unsubscribeOnContainerRemoval = (): void => {
52+
if (container.nodeType === Node.ELEMENT_NODE) {
53+
events.off(container, DX_REMOVE_EVENT, onRemoved);
54+
}
55+
}
56+
3857
if (prevTemplateId) {
3958
templateId = prevTemplateId;
4059
} else {
@@ -44,7 +63,11 @@ function createDxTemplate(
4463
renderedTemplates.set(key, templateId);
4564
}
4665
}
66+
67+
_subscribeOnContainerRemoval();
68+
4769
templatesStore.add(templateId, () => {
70+
4871
const props: ITemplateArgs = {
4972
data: data.model,
5073
index: data.index,
@@ -56,11 +79,9 @@ function createDxTemplate(
5679
{
5780
content: contentProvider(props),
5881
container,
59-
onRemoved: () => {
60-
templatesStore.setDeferredRemove(templateId, true);
61-
renderedTemplates.delete({ key1: data.model, key2: container });
62-
},
82+
onRemoved,
6383
onDidMount: () => {
84+
_unsubscribeOnContainerRemoval();
6485
templatesStore.setDeferredRemove(templateId, false);
6586
data.onRendered?.();
6687
},

0 commit comments

Comments
 (0)