Skip to content

Commit 0a2176b

Browse files
authored
Merge pull request #3319 from BSd3v/external-wrapper-temp-flag
adds flag to `ExternalWrapper` to identify if the component is a temporary insertion
2 parents 1951d67 + 13042c8 commit 0a2176b

File tree

4 files changed

+78
-6
lines changed

4 files changed

+78
-6
lines changed

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ import React from 'react';
22
import PropTypes from 'prop-types';
33

44

5-
const ExternalComponent = ({ id, text, input_id, extra_component }) => {
5+
const ExternalComponent = ({ id, text, input_id, extra_component, extra_component_temp }) => {
66
const ctx = window.dash_component_api.useDashContext();
77
const ExternalWrapper = window.dash_component_api.ExternalWrapper;
8-
98
return (
109
<div id={id}>
1110
{text && <ExternalWrapper
@@ -18,13 +17,15 @@ const ExternalComponent = ({ id, text, input_id, extra_component }) => {
1817
id: input_id
1918
}
2019
}}
21-
componentPath={[...ctx.componentPath, 'external']}
20+
componentPath={[JSON.stringify(ctx.componentPath), 'text']}
21+
temp={true}
2222
/>}
2323
{
2424
extra_component &&
2525
<ExternalWrapper
2626
component={extra_component}
27-
componentPath={[...ctx.componentPath, 'extra']}
27+
componentPath={[...ctx.componentPath, 'props', 'extra_component']}
28+
temp={extra_component_temp}
2829
/>}
2930
</div>
3031
)
@@ -39,6 +40,7 @@ ExternalComponent.propTypes = {
3940
namespace: PropTypes.string,
4041
props: PropTypes.object,
4142
}),
43+
extra_component_temp: PropTypes.bool,
4244
};
4345

4446
export default ExternalComponent;

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
99
- [#3279](https://github.com/plotly/dash/pull/3279) Fix an issue where persisted values were incorrectly pruned when updated via callback. Now, callback returned values are correctly stored in the persistence storage. Fix [#2678](https://github.com/plotly/dash/issues/2678)
1010
- [#3298](https://github.com/plotly/dash/pull/3298) Fix dev_only resources filtering.
1111
- [#3315](https://github.com/plotly/dash/pull/3315) Fix pages module is package check.
12+
- [#3319](https://github.com/plotly/dash/pull/3319) Fix issue where `ExternalWrapper` would remove props from the parent component, now there is a `temp` that is passed to check if it should be removed on unmount.
1213

1314
## Added
1415
- [#3294](https://github.com/plotly/dash/pull/3294) Added the ability to pass `allow_optional` to Input and State to allow callbacks to work even if these components are not in the dash layout.

dash/dash-renderer/src/wrapper/ExternalWrapper.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ import {
1313
type Props = {
1414
component: DashComponent;
1515
componentPath: DashLayoutPath;
16+
temp?: boolean; // If true, the component will be removed on unmount.
1617
};
1718

1819
/**
1920
* For rendering components that are out of the regular layout tree.
2021
*/
21-
function ExternalWrapper({component, componentPath}: Props) {
22+
function ExternalWrapper({component, componentPath, temp = false}: Props) {
2223
const dispatch: any = useDispatch();
2324
const [inserted, setInserted] = useState(false);
2425

@@ -33,7 +34,9 @@ function ExternalWrapper({component, componentPath}: Props) {
3334
);
3435
setInserted(true);
3536
return () => {
36-
dispatch(removeComponent({componentPath}));
37+
if (temp) {
38+
dispatch(removeComponent({componentPath}));
39+
}
3740
};
3841
}, []);
3942

tests/integration/renderer/test_external_component.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,69 @@ def click(*_):
5959
dash_duo.wait_for_text_to_equal("#out", "clicked")
6060

6161
assert dash_duo.get_logs() == []
62+
63+
64+
def test_rext002_render_external_component_temp(dash_duo):
65+
app = Dash()
66+
app.layout = html.Div(
67+
[
68+
dcc.Tabs(
69+
[
70+
dcc.Tab(
71+
label="Tab 1",
72+
children=[
73+
ExternalComponent(
74+
id="ext",
75+
extra_component={
76+
"type": "Div",
77+
"namespace": "dash_html_components",
78+
"props": {
79+
"id": "extra",
80+
"children": [
81+
html.Div(
82+
"extra children",
83+
id={"type": "extra", "index": 1},
84+
)
85+
],
86+
},
87+
},
88+
extra_component_temp=True,
89+
),
90+
],
91+
),
92+
dcc.Tab(
93+
label="Tab 2",
94+
children=[
95+
ExternalComponent(
96+
id="without-id",
97+
text="without-id",
98+
),
99+
],
100+
),
101+
]
102+
),
103+
]
104+
)
105+
106+
dash_duo.start_server(app)
107+
dash_duo.wait_for_text_to_equal("#extra", "extra children")
108+
109+
dash_duo.find_element(".tab:nth-child(2)").click()
110+
assert (
111+
dash_duo.find_element("#without-id > input").get_attribute("value")
112+
== "without-id"
113+
)
114+
115+
dash_duo.find_element(".tab").click()
116+
dash_duo.find_element("#ext")
117+
assert (
118+
len(dash_duo.find_elements("#ext > *")) == 0
119+
), "extra component should be removed"
120+
121+
dash_duo.find_element(".tab:nth-child(2)").click()
122+
assert (
123+
dash_duo.find_element("#without-id > input").get_attribute("value")
124+
== "without-id"
125+
)
126+
127+
assert dash_duo.get_logs() == []

0 commit comments

Comments
 (0)