python - Plotly Dash:删除元素后自动触发下载
问题描述
如您所见,如果我按下下载按钮,下载弹出窗口就会出现。下载后,如果我尝试删除其他卡,下载弹出窗口再次出现。为什么会这样?
这是一个最小的可重现示例
重现步骤
- 按下载按钮并下载或取消您喜欢的任何内容
- 现在尝试通过按删除按钮删除其他卡
观察: 下载弹窗应该又来了
import json
import dash
import dash_bootstrap_components as dbc
from dash import dcc
from dash.dependencies import Input, Output, ALL, State
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = dbc.Container([
dbc.Row([
dcc.Download(id="download-1"),
'card 1',
dbc.Col(dbc.Button('download', id='download-btn-1')),
dbc.Col(dbc.Button('delete', id={'type': 'delete', 'id': 'card-1'}))
], className='bg-warning m-2 p-2', id='card-1'),
dbc.Row([
dcc.Download(id="download-2"),
'card 2',
dbc.Col(dbc.Button('download', id='download-btn-2')),
dbc.Col(dbc.Button('delete', id={'type': 'delete', 'id': 'card-2'}))
], className='bg-warning m-2 p-2', id='card-2'),
dbc.Row([
dcc.Download(id="download-3"),
'card 3',
dbc.Col(dbc.Button('download', id='download-btn-3')),
dbc.Col(dbc.Button('delete', id={'type': 'delete', 'id': 'card-3'}))
], className='bg-warning m-2 p-2', id='card-3'),
], id='container-body')
@app.callback(
Output('download-1', 'data'),
Input('download-btn-1', 'n_clicks'),
prevent_initial_call=True
)
def download_1(n_clicks):
return dict(content="data 1", filename="hello.txt")
@app.callback(
Output('download-2', 'data'),
Input('download-btn-2', 'n_clicks'),
prevent_initial_call=True
)
def download_1(n_clicks):
return dict(content="data 2", filename="hello.txt")
@app.callback(
Output('download-3', 'data'),
Input('download-btn-3', 'n_clicks'),
prevent_initial_call=True
)
def download_1(n_clicks):
return dict(content="data 3", filename="hello.txt")
@app.callback(
Output('container-body', 'children'),
Input({'type': 'delete', 'id': ALL}, 'n_clicks'),
State('container-body', 'children'),
prevent_initial_call=True
)
def delete_children(n_clicks, children):
card_id_to_be_deleted = json.loads(dash.callback_context.triggered[0]['prop_id'].split('.')[0])['id']
index_to_be_deleted = None
for index, c in enumerate(children):
if c['props']['id'] == card_id_to_be_deleted:
index_to_be_deleted = index
break
children.pop(index_to_be_deleted)
return children
if __name__ == '__main__':
app.run_server(debug=True)
解决方案
除了其他答案之外,还提供更多上下文。
我认为正在发生的事情是您的delete_children
回调导致Download
组件重新安装并因此更新。
下载组件使用componentDidUpdate
React 生命周期方法。在componentDidMount
它内部检查是否data
不是null
或是否data
等于 的先前值data
。如果不是这样,则触发保存对话框(source)。
单击第一个下载按钮后,data
第一个下载组件的属性值不为空,并且与之前的状态(空)不同。因此,当delete_children
触发回调时,componentDidUpdate
会调用下载组件,下载组件会检测到data
已更改且不为空,因此会触发保存对话框。
因此,并不是在您的delete_children
回调之后触发了您的下载回调(您可以通过在每个下载回调中记录一些内容来检查这是否没有发生)。这是下载组件的更新,其中一些组件检测到它们应该根据它们的data
属性值触发保存。
您还会注意到,如果您按下载按钮 1,然后按下载按钮 2,然后按删除按钮 3,则会依次弹出两个保存对话框。两个下载组件的值发生data
了变化,并且调用了下载组件的componentDidMount
方法,因此出现了两个保存对话框。
推荐阅读
- java - 汇总子列表索引为数字的列表列表
- python - Python 请求在读取时挂起
- javascript - 字符串文字中的 HTML 标记未正确传递给 JS 方法
- javascript - C# MVC Datatable 只显示 1000 行,即使数据更少
- c# - 如何检查物体是否在球体的顶部或底部碰撞
- java - 如何在 Spring-boot 中使用 ContextJNDISelector
- memory - 堆栈字长可以不同于寄存器字长吗
- java - 使用 for 循环多次调用字符方法。然后 for 循环会将每个字符转换为字符串
- reactjs - 材质 UI V5:makeStyles 在材质 ui V5 中不起作用
- c++ - 同一共享对象调用的多次加载(dlopen)和卸载(dlclose)导致分段错误