You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Dash应用动态更新块时如何保存按钮n_clicks会话状态?

解决Dash动态组件刷新后隐藏状态丢失且会话独立的问题

要解决这个问题,核心是用会话级状态存储保存每个用户的模块隐藏状态,避免页面刷新时重置按钮状态。Dash的dcc.Store组件正好满足需求——它会为每个用户会话独立存储数据,不会在用户间共享。

关键实现步骤

  1. 添加会话级状态存储:在布局中加入dcc.Store,用字典结构保存每个模块的按钮点击次数
  2. 组件生成时读取存储状态:生成卡片组件时,从Store中读取对应模块的状态,设置按钮初始点击次数和卡片样式
  3. 同步状态到存储:修改隐藏/显示回调,将按钮点击状态同步到Store中
  4. 数据更新时复用存储状态:数据刷新回调读取Store状态,确保组件重建后保持之前的隐藏状态

修改后的完整代码

from dash import dcc, html, Input, Output, callback, MATCH, ctx, State
from datetime import datetime
import dash_bootstrap_components as dbc

refreshing_data = [
    [],
    [],
    [],
    [[1, '16/09 12:00', 'name', 'https://google.com/', 'status', '1 day 1 h', '1 day 1 h']],
    [[1, '16/09 12:00', 'name', 'https://google.com/', 'status', '1 day 1 h', '1 day 1 h']],
    [],
    [],
    [],
    [],
    [],
    [[1, '16/09 12:00', 'name', 'https://google.com/', 'status', '1 day 1 h', '1 day 1 h']],
    'Last refresh at 15:19'
]

switch_case = {
    0: 'H0',
    1: 'H1',
    2: 'H2',
    3: 'H3',
    4: 'H4',
    5: 'H5',
    6: 'H6',
    7: 'H7',
    8: 'H8',
    9: 'H9',
    10: 'H10'
}


def template_small_card(row):
    date_req = row[1]
    operation = row[2]
    link = row[3]
    status = row[4]
    card = html.Div([
        html.H6("Content is {}, {}, {}, {}".format(date_req, operation, link, status))
    ])
    return card


def template_big_card(list_of_small_cards, big_name, hidden_states):
    # 读取当前模块的历史点击次数,默认0
    module_index = big_name
    n_clicks = hidden_states.get(module_index, 0)
    # 根据点击次数设置初始显示状态
    initial_style = {'display': 'none'} if n_clicks % 2 == 1 else {}
    
    card = html.Div(
        [
            html.Div([
                html.Div(
                    [
                        html.Button(children=[html.Img(src='assets/vector1.png')],
                                    n_clicks=n_clicks,
                                    id={"type": "dynamic-button", "index": module_index},
                                    ),
                    ]
                ),
                html.Div([
                    html.H4("{}".format(big_name), className="card-title"),
                ]),
            ]),
            html.Hr(),
            html.Div(
                [*list_of_small_cards],
                id={"type": "dynamic-card", "index": module_index},
                style=initial_style
            )
        ]
    )
    return dbc.Row(children=[card], className="g-0")


def generate_big_card(data, big_name, hidden_states):
    if not data:
        return []
    else:
        result = [template_small_card(ind) for ind in data]
        big_card = template_big_card(result, switch_case[big_name], hidden_states)
        return big_card


layout = html.Div([
    html.Div('Request queue'),
    html.H6(id='time_update_1_vert'),
    dcc.Interval(
        id='interval-component_vert',
        interval=30 * 1000,  # 修正为30秒刷新间隔
        n_intervals=0
    ),
    # 会话级存储,保存每个模块的点击状态,关闭页面自动清空
    dcc.Store(id='hidden-models-store', storage_type='memory', data={}),
    dbc.Row(id='row-tables_vert')
])


@callback(
    Output('time_update_1_vert', 'children'),
    Output('row-tables_vert', 'children'),
    Input('interval-component_vert', 'n_intervals'),
    State('hidden-models-store', 'data'),
)
def update_data(n_intervals, hidden_states):
    list_of_df = refreshing_data
    columns_for_row = []
    time_update = datetime.today().strftime('%Y-%m-%d %H:%M:%S')
    for i in range(0, 11):
        dbc_column = generate_big_card(list_of_df[i], i, hidden_states)
        if dbc_column:
            columns_for_row.append(dbc_column)
    return time_update, columns_for_row


@callback(
    Output({"type": "dynamic-card", "index": MATCH}, "style"),
    Output('hidden-models-store', 'data'),
    Input({"type": "dynamic-button", "index": MATCH}, "n_clicks"),
    State('hidden-models-store', 'data'),
    State({"type": "dynamic-button", "index": MATCH}, "id"),
)
def update_card(n_clicks, hidden_states, button_id):
    module_index = button_id['index']
    # 更新当前模块的点击状态到存储
    hidden_states[module_index] = n_clicks
    # 计算当前显示样式
    style = {'display': 'none'} if n_clicks % 2 == 1 else {}
    return style, hidden_states

核心修改说明

  • dcc.Store使用storage_type='memory',确保每个用户会话拥有独立的状态存储,不会跨用户共享
  • 数据刷新回调接收Store的状态作为参数,生成组件时复用该状态,避免按钮点击次数重置
  • 隐藏回调同步更新Store中的状态,保证页面刷新后组件状态与用户操作一致
  • 组件生成时直接根据存储状态设置初始样式和点击次数,彻底解决刷新后状态丢失问题

内容的提问来源于stack exchange,提问作者Mike Lvov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 03:25:08