While troubleshooting the problem of clearing adhoc filters and setting hide: VariableHide.hideVariable and then adding filters and setting variable hide back to Variable.dontHide I discovered some fundamental issues with useState and AdHocFiltersVariable
Problem with useState.
calling the useState hook from a component does not actually guarantee state updates as useState does not activate the source scene object. So what this means is that useState only works if there is something else keeping the object active (like the scene objects own Component). The VariableValueSelectWrapper uses variable.useState but when the variable was hidden it was deactivated (since it was only it's component that counted in the refCount).
Solution:
useState should also count as "refCount" activation and keep the source scene object alive.
Problem with AdHocFiltersVariable
It updated filterExpression inside a subscribeToState (subscribing to it's own state). This could then trigger another state update if the expression had changed. But this can cause a problem as the state update that updates filterExpression happens inside the subscribeToState callback the order of state updates could be mangled for other objects subscribing to the variable state.
Example.
setState (update filters) (state update A)
State change handler 1 triggers for update A (this is its own handler), it causes another setState with updated filterExpression (state update B)
State change handler 1 triggers for update B (does nothing as filters has not changed only filterExpression)
State change handler 2 triggers for update B (for some other component that subscribes to state)
State change handler 2 triggers for update A (for some other component that subscribes to state)
As you can see the other component subscribing to the variable state will get the first state change (with old filterExpression) as the last value. Could be fixed with updating filterExpresion inside a setTimeout but opted to update filterExpression inside an overridden setState function as this eliminates two state updates when updating filters.
Release notes
<SceneObject>.useState will now cause the scene object to be activated (if it was not already). When the component that calls <sceneObject>.useState unmounts it will deactivate the scene object if it was the last component to call useState on this instance.
The same is not true for <SceneObject>.subscribeToState, this function still does not cause the source object to be activated.
📦 Published PR as canary version: 4.4.2--canary.679.8556229462.0
:sparkles: Test out this PR locally via:
```bash
npm install @grafana/scenes@4.4.2--canary.679.8556229462.0
# or
yarn add @grafana/scenes@4.4.2--canary.679.8556229462.0
```
While troubleshooting the problem of clearing adhoc filters and setting hide: VariableHide.hideVariable and then adding filters and setting variable hide back to Variable.dontHide I discovered some fundamental issues with useState and AdHocFiltersVariable
Problem with useState.
Solution:
Problem with AdHocFiltersVariable
Example.
As you can see the other component subscribing to the variable state will get the first state change (with old filterExpression) as the last value. Could be fixed with updating filterExpresion inside a setTimeout but opted to update filterExpression inside an overridden setState function as this eliminates two state updates when updating filters.
Release notes
<SceneObject>.useState
will now cause the scene object to be activated (if it was not already). When the component that calls<sceneObject>.useState
unmounts it will deactivate the scene object if it was the last component to call useState on this instance.The same is not true for
<SceneObject>.subscribeToState
, this function still does not cause the source object to be activated.📦 Published PR as canary version:
4.4.2--canary.679.8556229462.0
:sparkles: Test out this PR locally via: ```bash npm install @grafana/scenes@4.4.2--canary.679.8556229462.0 # or yarn add @grafana/scenes@4.4.2--canary.679.8556229462.0 ```