Repository: DevExpress/devextreme-vue (ts)

Issue:
Duplicate Configuration._nestedConfigurations  added on each render
### Issue Type
bug report

### Description
The issue is related to all the components

#### Steps to Reproduce
e.g. DxPopup - DxToolbarItem
- add a DxPopup instance with a single DxToolbarItem
- check $_config._nestedConfigurations (one object)
- force Popup rerender (e.g. hide it)
- check $_config._nestedConfigurations (two object)

#### Current Behavior
duplicate nested configuration

#### Expected Behavior
single nested configuration for each config-component

### Environment Details
- devextreme-vue version: 18.1.7-alpha.10

Pull request:
 Fix nested config-components duplication
Fixes #178 

Patch:
diff --git a/src/core/component.ts b/src/core/component.ts
index 98ca629..8b17ea3 100644
--- a/src/core/component.ts
+++ b/src/core/component.ts
@@ -167,12 +167,13 @@ function extractChildren(children: VNode[], config: Configuration): VNode[] {
     if (!children || children.length === 0) { return children; }
 
     const nodes: VNode[] = [];
-    pullConfigurations(children, nodes, config);
+    config.cleanNested();
+    pullConfigComponents(children, nodes, config);
 
     return nodes;
 }
 
-function pullConfigurations(children: VNode[], nodes: VNode[], ownerConfig: Configuration): void {
+function pullConfigComponents(children: VNode[], nodes: VNode[], ownerConfig: Configuration): void {
 
     children.forEach((node) => {
         nodes.push(node);
@@ -195,7 +196,7 @@ function pullConfigurations(children: VNode[], nodes: VNode[], ownerConfig: Conf
             (node.componentOptions as any as IConfigurable).$_config = config;
 
             if (node.componentOptions.children) {
-                pullConfigurations(node.componentOptions.children as VNode[], nodes, config);
+                pullConfigComponents(node.componentOptions.children as VNode[], nodes, config);
             }
         }
     });
diff --git a/src/core/configuration.ts b/src/core/configuration.ts
index d7c4f31..c3e1cde 100644
--- a/src/core/configuration.ts
+++ b/src/core/configuration.ts
@@ -4,12 +4,12 @@ type UpdateFunc = (name: string, value: any) => void;
 
 class Configuration {
 
-    private readonly _nestedConfigurations: Configuration[];
     private readonly _name: string | null;
     private readonly _isCollectionItem: boolean;
     private readonly _collectionItemIndex: number | undefined;
     private readonly _initialValues: Record<string, any>;
     private readonly _updateFunc: UpdateFunc;
+    private _nestedConfigurations: Configuration[];
     private _optionChangedFunc: any;
 
     private _options: string[];
@@ -80,6 +80,10 @@ class Configuration {
         });
     }
 
+    public cleanNested() {
+        this._nestedConfigurations = [];
+    }
+
     public createNested(
         name: string,
         initialValues: Record<string, any>,


Test patch:
diff --git a/src/core/component.test.ts b/src/core/component.test.ts
index 52b73d6..0933fb5 100644
--- a/src/core/component.test.ts
+++ b/src/core/component.test.ts
@@ -344,7 +344,7 @@ describe("configuration", () => {
         expect(config.nested[0].collectionItemIndex).toBe(0);
     });
 
-    it("initializes nested config (several collectionItems)", () => {
+    it("initializes nested config (multiple collectionItems)", () => {
         const nestedCollectionItem = buildTestComponentCtor();
         (nestedCollectionItem as any as IConfigurationComponent).$_optionName = "nestedOption";
         (nestedCollectionItem as any as IConfigurationComponent).$_isCollectionItem = true;
@@ -472,7 +472,7 @@ describe("configuration", () => {
         expect(nestedConfig.nested[0].collectionItemIndex).toBe(0);
     });
 
-    it("initializes sub-nested config (collectionItem)", () => {
+    it("initializes sub-nested config (multiple collectionItems)", () => {
         const nestedCollectionItem = buildTestComponentCtor();
         (nestedCollectionItem as any as IConfigurationComponent).$_optionName = "subNestedOption";
         (nestedCollectionItem as any as IConfigurationComponent).$_isCollectionItem = true;
@@ -518,6 +518,31 @@ describe("configuration", () => {
         expect(nestedConfig.nested[2].collectionItemIndex).toBe(2);
     });
 
+    it("doesn't add duplicate nested config on render", (cb) => {
+        const vm = new Vue({
+            template:
+                `<test-component>` +
+                `  <nested :prop1="123" />` +
+                `</test-component>`,
+            components: {
+                TestComponent,
+                Nested
+            }
+        }).$mount();
+        const config = (vm.$children[0] as any as IConfigurable).$_config;
+
+        vm.$forceUpdate();
+
+        Vue.nextTick(() => {
+            try {
+                expect(config.nested).toHaveLength(1);
+            } catch (e) {
+                cb.fail(e);
+            }
+            cb();
+        });
+    });
+
 });
 
 describe("nested options", () => {
diff --git a/src/core/configuration.test.ts b/src/core/configuration.test.ts
index c16cdde..0007950 100644
--- a/src/core/configuration.test.ts
+++ b/src/core/configuration.test.ts
@@ -173,7 +173,7 @@ describe("initial configuration", () => {
         });
     });
 
-    it("pulls array of values from a coollectionItem nested (several values)", () => {
+    it("pulls array of values from a coollectionItem nested (multiple values)", () => {
         const root = createRootConfig(jest.fn());
 
         root.createNested("options", { propA: 123 }, true);