Repository: DevExpress/devextreme-react
Pull request #138 (2018-06-25 12:08:25)

Fix endless updating of a nested component


Patch:
diff --git a/example/data-grid-example.tsx b/example/data-grid-example.tsx
index da27ef8..e2dd8d2 100644
--- a/example/data-grid-example.tsx
+++ b/example/data-grid-example.tsx
@@ -1,12 +1,15 @@
 import * as React from "react";
 import Example from "./example-block";
 
+import { Template } from "../src/core/template";
+
 import CheckBox from "../src/ui/check-box";
 import DataGrid, {
     Column,
     FilterRow,
     Grouping,
     GroupPanel,
+    MasterDetail,
     Pager,
     Paging,
     Selection
@@ -15,6 +18,15 @@ import NumberBox from "../src/ui/number-box";
 
 import { sales } from "./data";
 
+const DetailComponent = (props: any) => {
+    return (
+        <p>Row data:
+            <br/>
+            {JSON.stringify(props.data)}
+        </p>
+    );
+};
+
 export default class extends React.Component<any, { expandAll: boolean, pageSize: number }> {
 
     constructor(props: any) {
@@ -73,6 +85,8 @@ export default class extends React.Component<any, { expandAll: boolean, pageSize
                         defaultPageIndex={2}
                         pageSize={this.state.pageSize}
                     />
+                    <MasterDetail enabled={true} template={"detail"} />
+                    <Template name={"detail"} component={DetailComponent} />
                 </DataGrid>
             </Example>
         );
diff --git a/src/core/nested-option.ts b/src/core/nested-option.ts
index c5fb7b1..6dafce6 100644
--- a/src/core/nested-option.ts
+++ b/src/core/nested-option.ts
@@ -45,11 +45,18 @@ class NestedOption<P> extends React.PureComponent<P, any> {
 
     public componentWillUpdate(nextProps: P) {
         if (this._isAttached) {
-            this._updateFunc(nextProps, this.props);
+            this._updateFunc(clearProps(nextProps), this.props);
         }
     }
 }
 
+function clearProps(props) {
+    const result = { ...props };
+    delete result.registerNestedOption;
+    delete result.updateFunc;
+    return result;
+}
+
 function createOptionComponent<P>(rawElement: React.ReactElement<P>, metaData: INestedOptionMeta) {
     return React.cloneElement(rawElement, metaData as any);
 }
diff --git a/src/core/options-manager.ts b/src/core/options-manager.ts
index 153a639..6cc98ff 100644
--- a/src/core/options-manager.ts
+++ b/src/core/options-manager.ts
@@ -37,7 +37,7 @@ class OptionsManager {
         this._registerNestedOption = this._registerNestedOption.bind(this);
 
         this.registerNestedOption = this.registerNestedOption.bind(this);
-        this.ensureNestedOption = this.ensureNestedOption.bind(this);
+        this._ensureNestedOption = this._ensureNestedOption.bind(this);
         this.handleOptionChange = this.handleOptionChange.bind(this);
         this.processChangedValues = this.processChangedValues.bind(this);
     }
@@ -184,7 +184,7 @@ class OptionsManager {
                 }
             );
 
-            const entry = this.ensureNestedOption(
+            const entry = this._ensureNestedOption(
                 optionName,
                 owningCollection || this._nestedOptions,
                 nestedOptionClass.type.DefaultsProps,
@@ -202,7 +202,7 @@ class OptionsManager {
         return null;
     }
 
-    private ensureNestedOption(
+    private _ensureNestedOption(
         name: string,
         optionsCollection: Record<string, INestedOptionDescr>,
         defaults: Record<string, any>,


Test patch:
diff --git a/src/core/__tests__/component.test.tsx b/src/core/__tests__/component.test.tsx
index d97d1c5..b031b99 100644
--- a/src/core/__tests__/component.test.tsx
+++ b/src/core/__tests__/component.test.tsx
@@ -56,7 +56,6 @@ describe("rendering", () => {
 
         expect(WidgetClass.mock.calls[1][1].children).toBeUndefined();
     });
-
 });
 
 describe("disposing", () => {
diff --git a/src/core/__tests__/nested-option.test.tsx b/src/core/__tests__/nested-option.test.tsx
index 1bd2df3..41f5820 100644
--- a/src/core/__tests__/nested-option.test.tsx
+++ b/src/core/__tests__/nested-option.test.tsx
@@ -159,6 +159,20 @@ describe("nested option", () => {
         expect(Widget.option.mock.calls[0]).toEqual(["option.a", 456]);
     });
 
+    it("is pulled after update without rubbish", () => {
+
+        const component = mount(
+            <TestComponent>
+                <NestedComponent a={123} />
+            </TestComponent>
+        );
+
+        component.setProps({ children: <NestedComponent a={456} />});
+        jest.runAllTimers();
+        expect(Widget.option.mock.calls.length).toBe(1);
+        expect(Widget.option.mock.calls[0]).toEqual(["option.a", 456]);
+    });
+
 });
 
 describe("nested sub-option", () => {
@@ -311,5 +325,4 @@ describe("nested sub-option", () => {
         expect(Widget.option.mock.calls.length).toBe(1);
         expect(Widget.option.mock.calls[0]).toEqual(["option.subOption.d", "def"]);
     });
-
 });