For lru_cache to work all of the inputs need to be hashable, which means the nested lists and dictionaries you get from selectedData is not going to work. I would recommend not applying lru_cache to the whole callback, but rather defining a separate function that you decorate, then calling that from inside the callback with arguments pulled out from selectedData.
Something like
@lru_cache()
def slow_computation(...):
# do something slowly
pass
@app.callback(
Output('table_products','figure'),
[Input('gross_margin','selectedData'),
Input('table_province','selectedData'),
Input('table_city','selectedData'),
Input('table_store','selectedData'),
Input('table_category','selectedData'),
]
)
def calc_category_trace(...):
# extract relevant, hashable data, e.g.
state = selected_data["points"][0]["x"]
# pass hashable, extracted data to decorated function
slow_computation(state, ...)