@app.callback improvements? (Trigger component, same Output multiple times, callback without Output, serverside store / callback cache)

Nice job! :tada:

Trigger & null Output

  • Really nice that Trigger can be now used for all callbacks! Also callbacks with Output are asked here so many times, and it makes perfectly sense to enable that functionality!
  • I feel that the Trigger and null Output are kind of pair: Trigger is “input without input” and “null Output” is, well, output without output. I think both of them are very welcomed functionalities to the dash ecosystem!

More relaxed argument syntax for @app.callback

  • Big thumbs up for this! Less things to remember = :+1:t2: :+1:t2: :+1:t2:

imports

I see you created a new Dash class, too! That is handy! The imports from dash are currently

from dash import Dash
from dash.dependencies import Output, Input, State

so I was wondering, would similar imports be easier to memorize:

from dash_extensions import Dash
from dash_extensions.dependencies import Output, Input, Trigger, State

? Of course, also the Output etc. could be just importable from dash_extensions root, if they are always imported with Dash (one less row in imports). This is matter of taste.

Comments on the “cache”

This is something I have been thinking. Caching in my head means that something computationally expensive is skipped if called with same arguments. Now, if we think about this, it is actually more like a server side version of dcc.Store, if I understand this correctly, isn’t it? So, maybe it could be named like server_store. Or, maybe I am wrong and it should have the name “cache” in it, since it uses a FileSystemCache.

Or should it be actually implemented as a new component?

For example, ServerStore, which would work like this:

from dash_extensions import ServerStore

app.layout = html.Div([
    html.Button("Query data", id="btn"), dcc.Dropdown(id="dd"), dcc.Graph(id="graph"), html.Div(id="log"),
    ServerStore(id='mystorage'), # Add Store component, like dcc.Store. It could store the "ID"/key for the storage, for example.  
])

@app.callback([Output("mystorage", "data"), Output("log", "children")],  
              Trigger("btn", "n_clicks"))  
def query_data():
    time.sleep(1)
    return px.data.gapminder(), "Query completed"

Now the ServerStore could also take the cache as keyword argument, but if user does not pass anything, it would default to FileSystemCache. I don’t know if there are technical difficulties implementing this but at least the naming convention and usage would be the similar as it has been with the dcc.Store, and it would be pretty clear from the name what it actually does. Any thoughts on this?