Skip to content

Commit 8b3f422

Browse files
authored
Merge pull request #3066 from plotly/fix/wrapper
Improve performance of context components re-rendering
2 parents 0e38ed2 + 3249e22 commit 8b3f422

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+1226
-1493
lines changed

@plotly/dash-generator-test-component-typescript/src/props.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export type TypescriptComponentProps = {
2525
array_obj?: {a: string}[];
2626
array_any?: any[];
2727
enum_string?: 'one' | 'two';
28+
enum_number?: 2 | 3 | 4 | 5 | 6;
2829
union?: number | string;
2930
union_shape?: {a: string} | string;
3031
array_union_shape?: ({a: string} | string)[];

@plotly/dash-test-components/src/components/AddPropsComponent.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@ const AddPropsComponent = (props) => {
77

88
return (
99
<div id={id}>
10-
{React.cloneElement(children, {
10+
{React.cloneElement(children, {
1111
receive: `Element #${id} pass`,
12-
id: id,
1312
})}
1413
</div>
1514
);

components/dash-core-components/src/components/Checklist.react.js

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import PropTypes from 'prop-types';
22
import {append, includes, without} from 'ramda';
33
import React, {Component} from 'react';
4+
45
import {sanitizeOptions} from '../utils/optionTypes';
6+
import LoadingElement from '../utils/LoadingElement';
57

68
/**
79
* Checklist is a component that encapsulates several checkboxes.
@@ -21,19 +23,11 @@ export default class Checklist extends Component {
2123
options,
2224
setProps,
2325
style,
24-
loading_state,
2526
value,
2627
inline,
2728
} = this.props;
2829
return (
29-
<div
30-
data-dash-is-loading={
31-
(loading_state && loading_state.is_loading) || undefined
32-
}
33-
id={id}
34-
style={style}
35-
className={className}
36-
>
30+
<LoadingElement id={id} style={style} className={className}>
3731
{sanitizeOptions(options).map(option => {
3832
return (
3933
<label
@@ -67,7 +61,7 @@ export default class Checklist extends Component {
6761
</label>
6862
);
6963
})}
70-
</div>
64+
</LoadingElement>
7165
);
7266
}
7367
}
@@ -192,24 +186,6 @@ Checklist.propTypes = {
192186
*/
193187
setProps: PropTypes.func,
194188

195-
/**
196-
* Object that holds the loading state object coming from dash-renderer
197-
*/
198-
loading_state: PropTypes.shape({
199-
/**
200-
* Determines if the component is loading or not
201-
*/
202-
is_loading: PropTypes.bool,
203-
/**
204-
* Holds which property is loading
205-
*/
206-
prop_name: PropTypes.string,
207-
/**
208-
* Holds the name of the component that is loading
209-
*/
210-
component_name: PropTypes.string,
211-
}),
212-
213189
/**
214190
* Used to allow user interactions in this component to be persisted when
215191
* the component - or the page - is refreshed. If `persisted` is truthy and

components/dash-core-components/src/components/Clipboard.react.js

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import PropTypes from 'prop-types';
33
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
44
import {faCopy, faCheckCircle} from '@fortawesome/free-regular-svg-icons';
55

6+
import LoadingElement from '../utils/LoadingElement';
7+
68
const clipboardAPI = navigator.clipboard;
79

810
function wait(ms) {
@@ -14,6 +16,8 @@ function wait(ms) {
1416
*/
1517

1618
export default class Clipboard extends React.Component {
19+
static contextType = window.dash_component_api.DashContext;
20+
1721
constructor(props) {
1822
super(props);
1923
this.copyToClipboard = this.copyToClipboard.bind(this);
@@ -96,7 +100,7 @@ export default class Clipboard extends React.Component {
96100
}
97101

98102
async loading() {
99-
while (this.props.loading_state?.is_loading) {
103+
while (this.context.isLoading()) {
100104
await wait(100);
101105
}
102106
}
@@ -124,24 +128,21 @@ export default class Clipboard extends React.Component {
124128
}
125129

126130
render() {
127-
const {id, title, className, style, loading_state} = this.props;
131+
const {id, title, className, style} = this.props;
128132
const copyIcon = <FontAwesomeIcon icon={faCopy} />;
129133
const copiedIcon = <FontAwesomeIcon icon={faCheckCircle} />;
130134
const btnIcon = this.state.copied ? copiedIcon : copyIcon;
131135

132136
return clipboardAPI ? (
133-
<div
137+
<LoadingElement
134138
id={id}
135139
title={title}
136140
style={style}
137141
className={className}
138142
onClick={this.onClickHandler}
139-
data-dash-is-loading={
140-
(loading_state && loading_state.is_loading) || undefined
141-
}
142143
>
143144
<i> {btnIcon}</i>
144-
</div>
145+
</LoadingElement>
145146
) : null;
146147
}
147148
}
@@ -196,24 +197,6 @@ Clipboard.propTypes = {
196197
*/
197198
className: PropTypes.string,
198199

199-
/**
200-
* Object that holds the loading state object coming from dash-renderer
201-
*/
202-
loading_state: PropTypes.shape({
203-
/**
204-
* Determines if the component is loading or not
205-
*/
206-
is_loading: PropTypes.bool,
207-
/**
208-
* Holds which property is loading
209-
*/
210-
prop_name: PropTypes.string,
211-
/**
212-
* Holds the name of the component that is loading
213-
*/
214-
component_name: PropTypes.string,
215-
}),
216-
217200
/**
218201
* Dash-assigned callback that gets fired when the value changes.
219202
*/

components/dash-core-components/src/components/ConfirmDialogProvider.react.js

Lines changed: 8 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import {clone} from 'ramda';
21
import React from 'react';
32
import PropTypes from 'prop-types';
43

54
import ConfirmDialog from './ConfirmDialog.react';
5+
import LoadingElement from '../utils/LoadingElement';
66

77
/**
88
* A wrapper component that will display a confirmation dialog
@@ -18,30 +18,21 @@ import ConfirmDialog from './ConfirmDialog.react';
1818
*/
1919
export default class ConfirmDialogProvider extends React.Component {
2020
render() {
21-
const {displayed, id, setProps, children, loading_state} = this.props;
21+
const {displayed, id, setProps, children} = this.props;
2222

2323
// Will lose the previous onClick of the child
24-
const wrapClick = child => {
25-
const props = clone(child.props);
26-
props._dashprivate_layout.props.onClick = () => {
27-
setProps({displayed: true});
28-
};
29-
30-
return React.cloneElement(child, props);
31-
};
24+
const wrapClick = child =>
25+
React.cloneElement(child, {
26+
onClick: () => setProps({displayed: true}),
27+
});
3228

3329
return (
34-
<div
35-
id={id}
36-
data-dash-is-loading={
37-
(loading_state && loading_state.is_loading) || undefined
38-
}
39-
>
30+
<LoadingElement id={id}>
4031
{Array.isArray(children)
4132
? children.map(wrapClick)
4233
: wrapClick(children)}
4334
<ConfirmDialog {...this.props} displayed={displayed} />
44-
</div>
35+
</LoadingElement>
4536
);
4637
}
4738
}
@@ -94,22 +85,4 @@ ConfirmDialogProvider.propTypes = {
9485
* The children to hijack clicks from and display the popup.
9586
*/
9687
children: PropTypes.any,
97-
98-
/**
99-
* Object that holds the loading state object coming from dash-renderer
100-
*/
101-
loading_state: PropTypes.shape({
102-
/**
103-
* Determines if the component is loading or not
104-
*/
105-
is_loading: PropTypes.bool,
106-
/**
107-
* Holds which property is loading
108-
*/
109-
prop_name: PropTypes.string,
110-
/**
111-
* Holds the name of the component that is loading
112-
*/
113-
component_name: PropTypes.string,
114-
}),
11588
};

components/dash-core-components/src/components/DatePickerRange.react.js

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -222,24 +222,6 @@ DatePickerRange.propTypes = {
222222
*/
223223
setProps: PropTypes.func,
224224

225-
/**
226-
* Object that holds the loading state object coming from dash-renderer
227-
*/
228-
loading_state: PropTypes.shape({
229-
/**
230-
* Determines if the component is loading or not
231-
*/
232-
is_loading: PropTypes.bool,
233-
/**
234-
* Holds which property is loading
235-
*/
236-
prop_name: PropTypes.string,
237-
/**
238-
* Holds the name of the component that is loading
239-
*/
240-
component_name: PropTypes.string,
241-
}),
242-
243225
/**
244226
* Used to allow user interactions in this component to be persisted when
245227
* the component - or the page - is refreshed. If `persisted` is truthy and

components/dash-core-components/src/components/DatePickerSingle.react.js

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -181,24 +181,6 @@ DatePickerSingle.propTypes = {
181181
*/
182182
setProps: PropTypes.func,
183183

184-
/**
185-
* Object that holds the loading state object coming from dash-renderer
186-
*/
187-
loading_state: PropTypes.shape({
188-
/**
189-
* Determines if the component is loading or not
190-
*/
191-
is_loading: PropTypes.bool,
192-
/**
193-
* Holds which property is loading
194-
*/
195-
prop_name: PropTypes.string,
196-
/**
197-
* Holds the name of the component that is loading
198-
*/
199-
component_name: PropTypes.string,
200-
}),
201-
202184
/**
203185
* Used to allow user interactions in this component to be persisted when
204186
* the component - or the page - is refreshed. If `persisted` is truthy and

components/dash-core-components/src/components/Dropdown.react.js

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -177,24 +177,6 @@ Dropdown.propTypes = {
177177
*/
178178
setProps: PropTypes.func,
179179

180-
/**
181-
* Object that holds the loading state object coming from dash-renderer
182-
*/
183-
loading_state: PropTypes.shape({
184-
/**
185-
* Determines if the component is loading or not
186-
*/
187-
is_loading: PropTypes.bool,
188-
/**
189-
* Holds which property is loading
190-
*/
191-
prop_name: PropTypes.string,
192-
/**
193-
* Holds the name of the component that is loading
194-
*/
195-
component_name: PropTypes.string,
196-
}),
197-
198180
/**
199181
* Used to allow user interactions in this component to be persisted when
200182
* the component - or the page - is refreshed. If `persisted` is truthy and

components/dash-core-components/src/components/Graph.react.js

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -556,24 +556,6 @@ PlotlyGraph.propTypes = {
556556
* Function that updates the state tree.
557557
*/
558558
setProps: PropTypes.func,
559-
560-
/**
561-
* Object that holds the loading state object coming from dash-renderer
562-
*/
563-
loading_state: PropTypes.shape({
564-
/**
565-
* Determines if the component is loading or not
566-
*/
567-
is_loading: PropTypes.bool,
568-
/**
569-
* Holds which property is loading
570-
*/
571-
prop_name: PropTypes.string,
572-
/**
573-
* Holds the name of the component that is loading
574-
*/
575-
component_name: PropTypes.string,
576-
}),
577559
};
578560

579561
ControlledPlotlyGraph.propTypes = PlotlyGraph.propTypes;

components/dash-core-components/src/components/Input.react.js

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import React, {PureComponent} from 'react';
33
import PropTypes from 'prop-types';
44
import isNumeric from 'fast-isnumeric';
55
import './css/input.css';
6+
import LoadingElement from '../utils/LoadingElement';
67

78
// eslint-disable-next-line no-implicit-coercion
89
const convert = val => (isNumeric(val) ? +val : NaN);
@@ -94,14 +95,11 @@ export default class Input extends PureComponent {
9495
render() {
9596
const valprops =
9697
this.props.type === 'number' ? {} : {value: this.state.value};
97-
const {loading_state} = this.props;
9898
let {className} = this.props;
9999
className = 'dash-input' + (className ? ` ${className}` : '');
100100
return (
101-
<input
102-
data-dash-is-loading={
103-
(loading_state && loading_state.is_loading) || undefined
104-
}
101+
<LoadingElement
102+
elementType={'input'}
105103
className={className}
106104
ref={this.input}
107105
onBlur={this.onBlur}
@@ -471,24 +469,6 @@ Input.propTypes = {
471469
*/
472470
setProps: PropTypes.func,
473471

474-
/**
475-
* Object that holds the loading state object coming from dash-renderer
476-
*/
477-
loading_state: PropTypes.shape({
478-
/**
479-
* Determines if the component is loading or not
480-
*/
481-
is_loading: PropTypes.bool,
482-
/**
483-
* Holds which property is loading
484-
*/
485-
prop_name: PropTypes.string,
486-
/**
487-
* Holds the name of the component that is loading
488-
*/
489-
component_name: PropTypes.string,
490-
}),
491-
492472
/**
493473
* Used to allow user interactions in this component to be persisted when
494474
* the component - or the page - is refreshed. If `persisted` is truthy and

0 commit comments

Comments
 (0)