Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Queue state updates to trigger re-render after current update cycle #116

Closed
Tracked by #50
mofojed opened this issue Nov 15, 2023 · 2 comments · Fixed by #182
Closed
Tracked by #50

Queue state updates to trigger re-render after current update cycle #116

mofojed opened this issue Nov 15, 2023 · 2 comments · Fixed by #182
Assignees

Comments

@mofojed
Copy link
Member

mofojed commented Nov 15, 2023

This is consistent with the React model.

This was referenced Nov 15, 2023
@niloc132
Copy link
Member

Two observations:

  • Calling more than one use_state setter callback from an event handler lambda appears to cause the component to re-render twice (arguably the first re-render is while in an inconsistent state, at least relative to how this would work in JS?)
  • Calling a use_state setter with the value it already has currently causes a re-render (which I am presently abusing), but perhaps should instead of a no-op.

@mofojed mofojed self-assigned this Dec 11, 2023
@mofojed
Copy link
Member Author

mofojed commented Dec 20, 2023

A sample snippet to test this out. Create a component with two state variables that should be kept in lock step. Print in each render loop. We should only see one line printed for each press of the button, and a and b should always be equal. Currently we see two lines of output for each button press.

import deephaven.ui as ui
from deephaven.ui import use_state


@ui.component
def foo():
    a, set_a = use_state(0)
    b, set_b = use_state(0)

    print(f"Render with a {a} and b {b}")

    def handle_press():
        set_a(a + 1)
        set_b(b + 1)

    return ui.action_button(
        f"a is {a} and b is {b}", on_press=handle_press
    )


f = foo()

mofojed added a commit to mofojed/deephaven-plugins that referenced this issue Dec 20, 2023
- Now updates are all queued on the same thread
- Fixes deephaven#116
mofojed added a commit to mofojed/deephaven-plugins that referenced this issue Jan 10, 2024
- Now updates are all queued on the same thread
- Fixes deephaven#116
mofojed added a commit to mofojed/deephaven-plugins that referenced this issue Jan 12, 2024
- Now updates are all queued on the same thread
- Fixes deephaven#116
mofojed added a commit that referenced this issue Jan 19, 2024
- Create a thread and queue for applying state updates
- Now callbacks and state updates are all queued on the same thread
- Cleaned up some typing in the `Renderer` class
- Added a `use_render_queue` hook and example for showing how to queue
state updates
- Fixes #116
- Tested using the snippet from #116:
```python
import deephaven.ui as ui
from deephaven.ui import use_state


@ui.component
def foo():
    a, set_a = use_state(0)
    b, set_b = use_state(0)

    print(f"Render with a {a} and b {b}")

    def handle_press():
        set_a(a + 1)
        set_b(b + 1)

    return ui.action_button(
        f"a is {a} and b is {b}", on_press=handle_press
    )


f = foo()
```
- Ensured that the print out was only printed once per press of the
button, and both values stayed the same
- Allow a callable to be passed into the use_state setter function that
takes the old value as a parameter. Tested using the following
component:
```python
import deephaven.ui as ui
from deephaven.ui import use_state


@ui.component
def bar():
    x, set_x = use_state(0)

    print(f"Render with x {x}")

    def handle_press():
        # Call set_x twice in the same method, using a callable. This should result in x increasing by 2 each time the button is pressed
        set_x(lambda old_x: old_x + 1)
        set_x(lambda old_x: old_x + 1)

    return ui.action_button(
        f"x is {x}", on_press=handle_press
    )


b = bar()
```
- Tested that trying to update state from the wrong thread throws an
error:
```python
import deephaven.ui as ui
import threading
import time
from deephaven.ui import use_state


@ui.component
def foo():
    a, set_a = use_state(0)
    b, set_b = use_state(0)

    print(f"Render with a {a} and b {b}")

    def handle_press():
        def update_state():
            time.sleep(1)
            set_a(a + 1)
            set_b(b + 1)
        # Not using the correct thread
        threading.Thread(target=update_state).start()

    return ui.action_button(
        f"a is {a} and b is {b}", on_press=handle_press
    )


f = foo()
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants