diff --git a/@plotly/dash-test-components/src/components/ExternalComponent.js b/@plotly/dash-test-components/src/components/ExternalComponent.js
index 64d2efc515..8c592e33de 100644
--- a/@plotly/dash-test-components/src/components/ExternalComponent.js
+++ b/@plotly/dash-test-components/src/components/ExternalComponent.js
@@ -2,10 +2,9 @@ import React from 'react';
import PropTypes from 'prop-types';
-const ExternalComponent = ({ id, text, input_id, extra_component }) => {
+const ExternalComponent = ({ id, text, input_id, extra_component, extra_component_temp }) => {
const ctx = window.dash_component_api.useDashContext();
const ExternalWrapper = window.dash_component_api.ExternalWrapper;
-
return (
{text && {
id: input_id
}
}}
- componentPath={[...ctx.componentPath, 'external']}
+ componentPath={[JSON.stringify(ctx.componentPath), 'text']}
+ temp={true}
/>}
{
extra_component &&
}
)
@@ -39,6 +40,7 @@ ExternalComponent.propTypes = {
namespace: PropTypes.string,
props: PropTypes.object,
}),
+ extra_component_temp: PropTypes.bool,
};
export default ExternalComponent;
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 499c393eca..90c2d0bd2f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
- [#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)
- [#3298](https://github.com/plotly/dash/pull/3298) Fix dev_only resources filtering.
- [#3315](https://github.com/plotly/dash/pull/3315) Fix pages module is package check.
+- [#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.
## Added
- [#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.
diff --git a/dash/dash-renderer/src/wrapper/ExternalWrapper.tsx b/dash/dash-renderer/src/wrapper/ExternalWrapper.tsx
index a6b1dad13f..78807b2145 100644
--- a/dash/dash-renderer/src/wrapper/ExternalWrapper.tsx
+++ b/dash/dash-renderer/src/wrapper/ExternalWrapper.tsx
@@ -13,12 +13,13 @@ import {
type Props = {
component: DashComponent;
componentPath: DashLayoutPath;
+ temp?: boolean; // If true, the component will be removed on unmount.
};
/**
* For rendering components that are out of the regular layout tree.
*/
-function ExternalWrapper({component, componentPath}: Props) {
+function ExternalWrapper({component, componentPath, temp = false}: Props) {
const dispatch: any = useDispatch();
const [inserted, setInserted] = useState(false);
@@ -33,7 +34,9 @@ function ExternalWrapper({component, componentPath}: Props) {
);
setInserted(true);
return () => {
- dispatch(removeComponent({componentPath}));
+ if (temp) {
+ dispatch(removeComponent({componentPath}));
+ }
};
}, []);
diff --git a/tests/integration/renderer/test_external_component.py b/tests/integration/renderer/test_external_component.py
index c0ab76fcc3..ec2fcfef12 100644
--- a/tests/integration/renderer/test_external_component.py
+++ b/tests/integration/renderer/test_external_component.py
@@ -59,3 +59,69 @@ def click(*_):
dash_duo.wait_for_text_to_equal("#out", "clicked")
assert dash_duo.get_logs() == []
+
+
+def test_rext002_render_external_component_temp(dash_duo):
+ app = Dash()
+ app.layout = html.Div(
+ [
+ dcc.Tabs(
+ [
+ dcc.Tab(
+ label="Tab 1",
+ children=[
+ ExternalComponent(
+ id="ext",
+ extra_component={
+ "type": "Div",
+ "namespace": "dash_html_components",
+ "props": {
+ "id": "extra",
+ "children": [
+ html.Div(
+ "extra children",
+ id={"type": "extra", "index": 1},
+ )
+ ],
+ },
+ },
+ extra_component_temp=True,
+ ),
+ ],
+ ),
+ dcc.Tab(
+ label="Tab 2",
+ children=[
+ ExternalComponent(
+ id="without-id",
+ text="without-id",
+ ),
+ ],
+ ),
+ ]
+ ),
+ ]
+ )
+
+ dash_duo.start_server(app)
+ dash_duo.wait_for_text_to_equal("#extra", "extra children")
+
+ dash_duo.find_element(".tab:nth-child(2)").click()
+ assert (
+ dash_duo.find_element("#without-id > input").get_attribute("value")
+ == "without-id"
+ )
+
+ dash_duo.find_element(".tab").click()
+ dash_duo.find_element("#ext")
+ assert (
+ len(dash_duo.find_elements("#ext > *")) == 0
+ ), "extra component should be removed"
+
+ dash_duo.find_element(".tab:nth-child(2)").click()
+ assert (
+ dash_duo.find_element("#without-id > input").get_attribute("value")
+ == "without-id"
+ )
+
+ assert dash_duo.get_logs() == []