From 3ff6fb31cd17b281762fd044a8b8a088bb1c4c21 Mon Sep 17 00:00:00 2001 From: mikebender Date: Mon, 11 Nov 2024 11:47:11 -0500 Subject: [PATCH 01/11] WIP docs for hooks overview --- plugins/ui/docs/hooks/README.md | 28 ++++++++++++++++++++++++++++ plugins/ui/docs/sidebar.json | 4 ++++ 2 files changed, 32 insertions(+) create mode 100644 plugins/ui/docs/hooks/README.md diff --git a/plugins/ui/docs/hooks/README.md b/plugins/ui/docs/hooks/README.md new file mode 100644 index 000000000..a0f4813d8 --- /dev/null +++ b/plugins/ui/docs/hooks/README.md @@ -0,0 +1,28 @@ +# Hooks + +_Hooks_ let you use state and other deephaven.ui features in your components. They are a way to reuse stateful logic between components. Hooks are functions that let you "hook into" state and lifecycle features from function components. You can either use the built-in hooks or combine them to build your own. + +## Example + +```python +from deephaven import ui + + +@ui.component +def ui_counter(): + count, set_count = ui.use_state(0) + return ui.button(f"Pressed {count} times", on_press=lambda: set_count(count + 1)) + + +counter = ui_counter() +``` + +## UI recommendations + +1. **Hooks must be used within components or other hooks**: Hooks require a rendering context, and therefore can only be used within component functions or other hooks. They cannot be used in regular Python functions or outside of components. +2. **All hooks start with `use_`**: For example, `use_state` is a hook that lets you add state to your components. +3. **Hooks must be called at the _top_ level**: Do not use hooks inside loops, conditions, or nested functions. This ensures that hooks are called in the same order each time a component renders. If you want to use one in a conditional or a loop, extract that logic to a new component and put it there. + +## Built-in hooks + +## Create custom hooks diff --git a/plugins/ui/docs/sidebar.json b/plugins/ui/docs/sidebar.json index a2c422874..a3d5221c3 100644 --- a/plugins/ui/docs/sidebar.json +++ b/plugins/ui/docs/sidebar.json @@ -146,6 +146,10 @@ { "label": "Hooks", "items": [ + { + "label" "Overview", + "path": "hooks/README.md" + }, { "label": "use_boolean", "path": "hooks/use_boolean.md" From e0ccfb214b7895ef33250452628937a9c8f319aa Mon Sep 17 00:00:00 2001 From: mikebender Date: Mon, 11 Nov 2024 17:57:57 -0500 Subject: [PATCH 02/11] More built in hooks and details --- plugins/ui/docs/hooks/README.md | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/plugins/ui/docs/hooks/README.md b/plugins/ui/docs/hooks/README.md index a0f4813d8..3663a68a6 100644 --- a/plugins/ui/docs/hooks/README.md +++ b/plugins/ui/docs/hooks/README.md @@ -25,4 +25,39 @@ counter = ui_counter() ## Built-in hooks +Below are all the built-in hooks that deephaven.ui provides. + +### State hooks + +_State_ lets a component remember some data between renders. State is a way to preserve data between renders and to trigger a re-render when the data changes. For example, a counter component might use state to keep track of the current count. + +To add state to a component, use the [`use_state`](use_state.md) hook. + +### Ref hooks + +_Refs_ provide a way to hold a value that isn't used for re-rendering. Unlike with state, updating a ref does not re-render your component. + +- [`use_ref`](use_ref.md) returns a mutable ref object whose `.current` property is initialized to the passed argument. + +### Effect hooks + +_Effects_ let you perform side effects in your components. Data fetching, setting up a subscription, and manually synchronizing with an external system are all examples of side effects. + +- [`use_effect`](use_effect.md) lets you perform side effects in your components. + +### Performance hooks + +_Performance_ hooks let you optimize components for performance. They allow you to memoize expensive computations so that you can avoid re-running them on every render, or skip unnecessary re-rendering. + +- [`use_memo`](use_memo.md) lets you memoize expensive computations. +- [`use_callback`](use_callback.md) lets you cache a function definition before passing it down to a child component, so that the child component doesn't re-render unnecessarily. + +### Data hooks + +_Data_ hooks let you use data from within a Deephaven table in your component. + +- [`use_table_data`](use_table_data.md) lets you use the full table contents. +- [`use_column_data`](use_column_data.md) lets you use the column data of one column. +- [`use_cell_data`](use_cell_data.md) lets you use the cell data of one cell. + ## Create custom hooks From e2bd6af053e72716e870444d28be75859303f3be Mon Sep 17 00:00:00 2001 From: Mike Bender Date: Mon, 11 Nov 2024 17:50:30 -0500 Subject: [PATCH 03/11] Add use_callback.md --- plugins/ui/docs/hooks/use_callback.md | 57 +++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 plugins/ui/docs/hooks/use_callback.md diff --git a/plugins/ui/docs/hooks/use_callback.md b/plugins/ui/docs/hooks/use_callback.md new file mode 100644 index 000000000..3dd002604 --- /dev/null +++ b/plugins/ui/docs/hooks/use_callback.md @@ -0,0 +1,57 @@ +# use_callback + +`use_callback` is a hook that memoizes a callback function, returning the same callback function on subsequent renders when the dependencies have not changed. This is useful when passing callbacks to functions or components that rely on reference equality to prevent unnecessary re-renders or effects from firing. + +## Example + +```python +from deephaven import ui +import time + + +@ui.component +def ui_server(): + theme, set_theme = ui.use_state("red") + + create_server = ui.use_callback(lambda: {"host": "localhost"}, []) + + def connect(): + server = create_server() + print(f"Connecting to {server}") + time.sleep(0.5) + + ui.use_effect(connect, [create_server]) + + return ui.view( + ui.picker( + "red", + "orange", + "yellow", + label="Theme", + selected_key=theme, + on_change=set_theme, + ), + padding="size-100", + background_color=theme, + ) + + +my_server = ui_server() +``` + +In the example above, the `create_server` callback is memoized using `use_callback`. The `connect` function is then passed to [`use_effect`](./use_effect.md) with `create_server` as a dependency. This ensures that the effect will not be triggered on every re-render because the `create_server` callback is memoized. + +`use_callback` is similar to [`use_memo`](./use_memo.md), but for functions instead of values. Use `use_callback` when you need to memoize a callback function that relies on reference equality to prevent unnecessary re-renders. + +## Recommendations + +Recommendations for memoizing callback functions: + +1. **Use memoization when callbacks passed into expensive effects**: If the callback is being passed into an expensive `use_effect` or `use_memo` call, `use_callback` so that it maintains referential equality. +2. **Use dependencies**: Pass in only the dependencies that the memoized callback relies on. If any of the dependencies change, the memoized callback will be re-computed. + +## API Reference + +```{eval-rst} +.. dhautofunction:: deephaven.ui.use_callback +``` From c376b5f9ff4eceead3cfd6a66b1da928a06d3c29 Mon Sep 17 00:00:00 2001 From: Mike Bender Date: Tue, 12 Nov 2024 09:12:02 -0500 Subject: [PATCH 04/11] Add a custom hook creation section --- plugins/ui/docs/hooks/README.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/plugins/ui/docs/hooks/README.md b/plugins/ui/docs/hooks/README.md index 3663a68a6..f76d89ced 100644 --- a/plugins/ui/docs/hooks/README.md +++ b/plugins/ui/docs/hooks/README.md @@ -50,7 +50,7 @@ _Effects_ let you perform side effects in your components. Data fetching, settin _Performance_ hooks let you optimize components for performance. They allow you to memoize expensive computations so that you can avoid re-running them on every render, or skip unnecessary re-rendering. - [`use_memo`](use_memo.md) lets you memoize expensive computations. -- [`use_callback`](use_callback.md) lets you cache a function definition before passing it down to a child component, so that the child component doesn't re-render unnecessarily. +- [`use_callback`](use_callback.md) lets you cache a function definition before passing to an effect or child component, preventing unnecessary rendering. It's like `use_memo` but specifically for functions. ### Data hooks @@ -61,3 +61,26 @@ _Data_ hooks let you use data from within a Deephaven table in your component. - [`use_cell_data`](use_cell_data.md) lets you use the cell data of one cell. ## Create custom hooks + +You can create your own hooks to reuse stateful logic between components. A custom hook is a JavaScript function whose name starts with `use` and that may call other hooks. For example, let's say you want to create a custom hook that checks whether a table cell is odd. You can create a custom hook called `use_is_cell_odd`: + +```python +from deephaven import time_table, ui + + +def use_is_cell_odd(table): + cell_value = ui.use_cell_data(table, 0) + return cell_value % 2 == 1 + + +@ui.component +def ui_table_odd_cell(table): + is_odd = use_is_cell_odd(table) + return ui.view(f"Is the cell odd? {is_odd}") + + +_table = time_table("PT1s").update("x=i").view("x").tail(1) +table_odd_cell = ui_table_odd_cell(_table) +``` + +Notice at the end of our custom hook, we check if the cell value is odd and return the result. We then use this custom hook in our component to display whether the cell is odd. From fc72cf92efbaec6e2dbca6ea2f1e1aeeb8dff4df Mon Sep 17 00:00:00 2001 From: Mike Bender Date: Tue, 12 Nov 2024 09:14:22 -0500 Subject: [PATCH 05/11] Update sidebar --- plugins/ui/docs/sidebar.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/ui/docs/sidebar.json b/plugins/ui/docs/sidebar.json index a3d5221c3..4f42ce53e 100644 --- a/plugins/ui/docs/sidebar.json +++ b/plugins/ui/docs/sidebar.json @@ -147,13 +147,17 @@ "label": "Hooks", "items": [ { - "label" "Overview", + "label": "Overview", "path": "hooks/README.md" }, { "label": "use_boolean", "path": "hooks/use_boolean.md" }, + { + "label": "use_callback", + "path": "hooks/use_callback.md" + }, { "label": "use_effect", "path": "hooks/use_effect.md" From b43eab0f2020b6f974fe57bc90339a8bd5a88416 Mon Sep 17 00:00:00 2001 From: mikebender Date: Tue, 12 Nov 2024 10:37:49 -0500 Subject: [PATCH 06/11] Add use_ref documentation --- plugins/ui/docs/hooks/use_ref.md | 80 ++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 plugins/ui/docs/hooks/use_ref.md diff --git a/plugins/ui/docs/hooks/use_ref.md b/plugins/ui/docs/hooks/use_ref.md new file mode 100644 index 000000000..99c76e262 --- /dev/null +++ b/plugins/ui/docs/hooks/use_ref.md @@ -0,0 +1,80 @@ +# use_ref + +`use_ref` returns a mutable ref object whose `.current` property is initialized to the passed argument. The returned object will persist for the full lifetime of the component. Updating the `.current` property will not trigger a re-render. + +## Example + +```python +from deephaven import ui + + +@ui.component +def ui_ref_counter(): + ref = ui.use_ref(0) + + def handle_press(): + ref.current += 1 + print(f"You clicked {ref.current} times!") + + return ui.button("Click me!", on_press=handle_press) + + +ref_counter = ui_ref_counter() +``` + +Note that we're only using the `ref.current` value within the `handle_press` method. This is because updating the ref does not trigger a re-render, so the component will not reflect the updated value. The value will be printed out each time you press the button. If you need to update the component based on the ref value, consider using `use_state` instead. + +## Recommendations + +1. **Use `use_ref` for mutable values**: If you need to store a mutable value that doesn't affect the component's rendering, use `use_ref`. +2. **Use `use_state` for values that affect rendering**: If you need to store a value that will affect the component's rendering, use `use_state` instead of `use_ref`. + +## Stopwatch example + +Here's an example of a stopwatch using `use_ref`. Press the Start button to start the stopwatch, and the Stop button to stop it. The elapsed time will be displayed in the text field: + +```python +from deephaven import ui +import datetime +from threading import Timer + + +class RepeatTimer(Timer): + def run(self): + while not self.finished.wait(self.interval): + self.function(*self.args, **self.kwargs) + + +@ui.component +def ui_stopwatch(): + start_time, set_start_time = ui.use_state(datetime.datetime.now()) + now, set_now = ui.use_state(start_time) + timer_ref = ui.use_ref(None) + + def stop(): + if timer_ref.current is not None: + timer_ref.current.cancel() + + def start(): + stop() + new_start_time = datetime.datetime.now() + set_start_time(new_start_time) + set_now(new_start_time) + timer_ref.current = RepeatTimer(0.01, lambda: set_now(datetime.datetime.now())) + timer_ref.current.start() + + return ui.view( + ui.heading(f"Elapsed time: {now - start_time}"), + ui.button("Start", on_press=start), + ui.button("Stop", on_press=stop), + ) + + +stopwatch = ui_stopwatch() +``` + +## API Reference + +```{eval-rst} +.. dhautofunction:: deephaven.ui.use_ref +``` From df50dd9ab25fc396fbcc66c56f64743e0cc4db7c Mon Sep 17 00:00:00 2001 From: mikebender Date: Tue, 12 Nov 2024 10:58:09 -0500 Subject: [PATCH 07/11] Add docs for use_cell_data, use_column_data, use_table_data --- plugins/ui/docs/hooks/use_cell_data.md | 31 ++++++++++++++++++++++++ plugins/ui/docs/hooks/use_column_data.md | 31 ++++++++++++++++++++++++ plugins/ui/docs/hooks/use_table_data.md | 31 ++++++++++++++++++++++++ plugins/ui/docs/sidebar.json | 16 ++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 plugins/ui/docs/hooks/use_cell_data.md create mode 100644 plugins/ui/docs/hooks/use_column_data.md create mode 100644 plugins/ui/docs/hooks/use_table_data.md diff --git a/plugins/ui/docs/hooks/use_cell_data.md b/plugins/ui/docs/hooks/use_cell_data.md new file mode 100644 index 000000000..dbfd03870 --- /dev/null +++ b/plugins/ui/docs/hooks/use_cell_data.md @@ -0,0 +1,31 @@ +# use_cell_data + +`use_cell_data` lets you use the cell data of the first cell in a table. This is useful when you want to listen to an updating table and use the data in your component. + +## Example + +```python +from deephaven import time_table, ui + + +@ui.component +def ui_table_first_cell(table): + cell_value = ui.use_cell_data(table) + return ui.heading(f"The first cell value is {cell_value}") + + +table_first_cell = ui_table_first_cell(time_table("PT1s").tail(1)) +``` + +In the above example, `ui_table_first_cell` is a component that listens to the last row of a table and displays the value of the first cell. The `cell_value` variable is updated every time the table updates. + +## Recommendations + +1. **Use `use_cell_data` for listening to table updates**: If you need to listen to a table for one cell of data, use `use_cell_data`. +2. **Use table operations to filter to one cell**: If your table has multiple rows and columns, use table operations such as `.where` and `.select` to filter to the cell you want to listen to. `use_cell_data` always uses the top-left cell of the table. + +## API Reference + +```{eval-rst} +.. dhautofunction:: deephaven.ui.use_cell_data +``` diff --git a/plugins/ui/docs/hooks/use_column_data.md b/plugins/ui/docs/hooks/use_column_data.md new file mode 100644 index 000000000..ea63cff92 --- /dev/null +++ b/plugins/ui/docs/hooks/use_column_data.md @@ -0,0 +1,31 @@ +# use_column_data + +`use_column_data` lets you use the column data of a table. This is useful when you want to listen to an updating table and use the data in your component. + +## Example + +```python +from deephaven import time_table, ui + + +@ui.component +def ui_table_column(table): + column_data = ui.use_column_data(table) + return ui.heading(f"The column data is {column_data}") + + +table_column = ui_table_column(time_table("PT1s").tail(5)) +``` + +In the above example, `ui_table_column` is a component that listens to the last 5 rows of a table and displays the values of the first column. The `column_data` variable is updated every time the table updates. + +## Recommendations + +1. **Use `use_column_data` for listening to table updates**: If you need to listen to a table for one column of data, use `use_column_data`. +2. **Use table operations to filter to one column**: If your table has multiple rows and columns, use table operations such as `.where` and `.select` to filter to the column you want to listen to. `use_column_data` always uses the first column of the table. + +## API Reference + +```{eval-rst} +.. dhautofunction:: deephaven.ui.use_column_data +``` diff --git a/plugins/ui/docs/hooks/use_table_data.md b/plugins/ui/docs/hooks/use_table_data.md new file mode 100644 index 000000000..80fa7edc0 --- /dev/null +++ b/plugins/ui/docs/hooks/use_table_data.md @@ -0,0 +1,31 @@ +# use_table_data + +`use_table_data` lets you use the data of a table. This is useful when you want to listen to an updating table and use the data in your component. + +## Example + +```python +from deephaven import time_table, ui + + +@ui.component +def ui_table_data(table): + table_data = ui.use_table_data(table) + return ui.heading(f"The table data is {table_data}") + + +table_data = ui_table_data(time_table("PT1s").update("x=i").tail(5)) +``` + +In the above example, `ui_table_data` is a component that listens to the last 5 rows of a table and displays the data. The `table_data` variable is updated every time the table updates. + +## Recommendations + +1. **Use `use_table_data` for listening to table updates**: If you need to listen to a table for all the data, use `use_table_data`. +2. **Use table operations to filter to the data you want**: If your table has multiple rows and columns, use table operations such as `.where` and `.select` to filter to the data you want to listen to. + +## API Reference + +```{eval-rst} +.. dhautofunction:: deephaven.ui.use_table_data +``` diff --git a/plugins/ui/docs/sidebar.json b/plugins/ui/docs/sidebar.json index 4f42ce53e..e3c9a2202 100644 --- a/plugins/ui/docs/sidebar.json +++ b/plugins/ui/docs/sidebar.json @@ -158,6 +158,14 @@ "label": "use_callback", "path": "hooks/use_callback.md" }, + { + "label": "use_cell_data", + "path": "hooks/use_cell_data.md" + }, + { + "label": "use_column_data", + "path": "hooks/use_column_data.md" + }, { "label": "use_effect", "path": "hooks/use_effect.md" @@ -166,9 +174,17 @@ "label": "use_memo", "path": "hooks/use_memo.md" }, + { + "label": "use_ref", + "path": "hooks/use_ref.md" + }, { "label": "use_state", "path": "hooks/use_state.md" + }, + { + "label": "use_table_data", + "path": "hooks/use_table_data.md" } ] } From 3f20daa64c4e2c5b42fbbf777e0ac556ca6f1855 Mon Sep 17 00:00:00 2001 From: Mike Bender Date: Tue, 12 Nov 2024 14:00:06 -0500 Subject: [PATCH 08/11] Apply suggestions from code review Co-authored-by: margaretkennedy <82049573+margaretkennedy@users.noreply.github.com> --- plugins/ui/docs/hooks/README.md | 12 ++++++------ plugins/ui/docs/hooks/use_callback.md | 4 ++-- plugins/ui/docs/hooks/use_cell_data.md | 2 +- plugins/ui/docs/hooks/use_ref.md | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/ui/docs/hooks/README.md b/plugins/ui/docs/hooks/README.md index f76d89ced..25bd327c8 100644 --- a/plugins/ui/docs/hooks/README.md +++ b/plugins/ui/docs/hooks/README.md @@ -29,19 +29,19 @@ Below are all the built-in hooks that deephaven.ui provides. ### State hooks -_State_ lets a component remember some data between renders. State is a way to preserve data between renders and to trigger a re-render when the data changes. For example, a counter component might use state to keep track of the current count. +_State_ lets a component remember some data between renders and trigger a re-render when the data changes. For example, a counter component might use state to keep track of the current count. -To add state to a component, use the [`use_state`](use_state.md) hook. +The [`use_state`](use_state.md) hook adds state to a component. ### Ref hooks -_Refs_ provide a way to hold a value that isn't used for re-rendering. Unlike with state, updating a ref does not re-render your component. +A _ref_ provides a way to hold a value that isn't used for re-rendering. Unlike with state, updating a ref does not re-render your component. - [`use_ref`](use_ref.md) returns a mutable ref object whose `.current` property is initialized to the passed argument. ### Effect hooks -_Effects_ let you perform side effects in your components. Data fetching, setting up a subscription, and manually synchronizing with an external system are all examples of side effects. +An _effect_ hook lets you perform side effects in your components; for example, data fetching, setting up a subscription, and manually synchronizing with an external system. - [`use_effect`](use_effect.md) lets you perform side effects in your components. @@ -57,8 +57,8 @@ _Performance_ hooks let you optimize components for performance. They allow you _Data_ hooks let you use data from within a Deephaven table in your component. - [`use_table_data`](use_table_data.md) lets you use the full table contents. -- [`use_column_data`](use_column_data.md) lets you use the column data of one column. -- [`use_cell_data`](use_cell_data.md) lets you use the cell data of one cell. +- [`use_column_data`](use_column_data.md) lets you use the data of one column. +- [`use_cell_data`](use_cell_data.md) lets you use the data of one cell. ## Create custom hooks diff --git a/plugins/ui/docs/hooks/use_callback.md b/plugins/ui/docs/hooks/use_callback.md index 3dd002604..4e71d7484 100644 --- a/plugins/ui/docs/hooks/use_callback.md +++ b/plugins/ui/docs/hooks/use_callback.md @@ -39,7 +39,7 @@ def ui_server(): my_server = ui_server() ``` -In the example above, the `create_server` callback is memoized using `use_callback`. The `connect` function is then passed to [`use_effect`](./use_effect.md) with `create_server` as a dependency. This ensures that the effect will not be triggered on every re-render because the `create_server` callback is memoized. +In the example above, `use_callback` memoizes the `create_server` callback. The `connect` function is then passed to [`use_effect`](./use_effect.md) with `create_server` as a dependency. This ensures the effect will not be triggered on every re-render because the `create_server` callback is memoized. `use_callback` is similar to [`use_memo`](./use_memo.md), but for functions instead of values. Use `use_callback` when you need to memoize a callback function that relies on reference equality to prevent unnecessary re-renders. @@ -47,7 +47,7 @@ In the example above, the `create_server` callback is memoized using `use_callba Recommendations for memoizing callback functions: -1. **Use memoization when callbacks passed into expensive effects**: If the callback is being passed into an expensive `use_effect` or `use_memo` call, `use_callback` so that it maintains referential equality. +1. **Use memoization when callbacks are passed into expensive effects**: If the callback is being passed into an expensive `use_effect` or `use_memo` call, use `use_callback` so that it maintains referential equality. 2. **Use dependencies**: Pass in only the dependencies that the memoized callback relies on. If any of the dependencies change, the memoized callback will be re-computed. ## API Reference diff --git a/plugins/ui/docs/hooks/use_cell_data.md b/plugins/ui/docs/hooks/use_cell_data.md index dbfd03870..6f0345a11 100644 --- a/plugins/ui/docs/hooks/use_cell_data.md +++ b/plugins/ui/docs/hooks/use_cell_data.md @@ -22,7 +22,7 @@ In the above example, `ui_table_first_cell` is a component that listens to the l ## Recommendations 1. **Use `use_cell_data` for listening to table updates**: If you need to listen to a table for one cell of data, use `use_cell_data`. -2. **Use table operations to filter to one cell**: If your table has multiple rows and columns, use table operations such as `.where` and `.select` to filter to the cell you want to listen to. `use_cell_data` always uses the top-left cell of the table. +2. **Use table operations to filter to one cell**: Because `use_cell_data` always uses the top-left cell of the table, you can filter your table to determine what cell to listen to. If your table has multiple rows and columns, use table operations such as `.where` and `.select` to filter to the desired cell. ## API Reference diff --git a/plugins/ui/docs/hooks/use_ref.md b/plugins/ui/docs/hooks/use_ref.md index 99c76e262..9e10468c7 100644 --- a/plugins/ui/docs/hooks/use_ref.md +++ b/plugins/ui/docs/hooks/use_ref.md @@ -31,7 +31,7 @@ Note that we're only using the `ref.current` value within the `handle_press` met ## Stopwatch example -Here's an example of a stopwatch using `use_ref`. Press the Start button to start the stopwatch, and the Stop button to stop it. The elapsed time will be displayed in the text field: +Here's an example of a stopwatch using `use_ref`. Press the **Start** button to start the stopwatch and the **Stop** button to stop it. The elapsed time will be displayed in the text field: ```python from deephaven import ui From a10e55692e956ad16ec03a4114dbcb0721513074 Mon Sep 17 00:00:00 2001 From: mikebender Date: Tue, 12 Nov 2024 14:00:25 -0500 Subject: [PATCH 09/11] Cleanup from review --- plugins/ui/docs/hooks/README.md | 2 +- plugins/ui/docs/hooks/use_cell_data.md | 2 +- plugins/ui/docs/hooks/use_column_data.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/ui/docs/hooks/README.md b/plugins/ui/docs/hooks/README.md index 25bd327c8..387bcbb43 100644 --- a/plugins/ui/docs/hooks/README.md +++ b/plugins/ui/docs/hooks/README.md @@ -1,6 +1,6 @@ # Hooks -_Hooks_ let you use state and other deephaven.ui features in your components. They are a way to reuse stateful logic between components. Hooks are functions that let you "hook into" state and lifecycle features from function components. You can either use the built-in hooks or combine them to build your own. +_Hooks_ let you use state and other deephaven.ui features in your components. Hooks are functions that let you "hook into" state and lifecycle features from function components, encapsulating code and logic to avoid duplication. You can either use the built-in hooks or combine them to build your own. ## Example diff --git a/plugins/ui/docs/hooks/use_cell_data.md b/plugins/ui/docs/hooks/use_cell_data.md index 6f0345a11..12195d688 100644 --- a/plugins/ui/docs/hooks/use_cell_data.md +++ b/plugins/ui/docs/hooks/use_cell_data.md @@ -1,6 +1,6 @@ # use_cell_data -`use_cell_data` lets you use the cell data of the first cell in a table. This is useful when you want to listen to an updating table and use the data in your component. +`use_cell_data` lets you use the cell data of the first cell (first row in the first column) in a table. This is useful when you want to listen to an updating table and use the data in your component. ## Example diff --git a/plugins/ui/docs/hooks/use_column_data.md b/plugins/ui/docs/hooks/use_column_data.md index ea63cff92..216dbce6d 100644 --- a/plugins/ui/docs/hooks/use_column_data.md +++ b/plugins/ui/docs/hooks/use_column_data.md @@ -1,6 +1,6 @@ # use_column_data -`use_column_data` lets you use the column data of a table. This is useful when you want to listen to an updating table and use the data in your component. +`use_column_data` lets you use the data of the first column of a table. This is useful when you want to listen to an updating table and use the data in your component. ## Example From cde78997eaf342311f2c7bb851c6accd4f7b6d30 Mon Sep 17 00:00:00 2001 From: mikebender Date: Tue, 12 Nov 2024 14:14:03 -0500 Subject: [PATCH 10/11] Add a tab switcher based on table data - Allows switching between tabs for an already filtered table. - Also added cases when _not_ to use `use_column_data` --- plugins/ui/docs/hooks/use_column_data.md | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/plugins/ui/docs/hooks/use_column_data.md b/plugins/ui/docs/hooks/use_column_data.md index 216dbce6d..b1f43d817 100644 --- a/plugins/ui/docs/hooks/use_column_data.md +++ b/plugins/ui/docs/hooks/use_column_data.md @@ -23,6 +23,36 @@ In the above example, `ui_table_column` is a component that listens to the last 1. **Use `use_column_data` for listening to table updates**: If you need to listen to a table for one column of data, use `use_column_data`. 2. **Use table operations to filter to one column**: If your table has multiple rows and columns, use table operations such as `.where` and `.select` to filter to the column you want to listen to. `use_column_data` always uses the first column of the table. +3. **Do not use `use_column_data` with [`list_view`](../components/list_view.md) or [`picker`](../components/picker.md)**: Some components are optimized to work with large tables of data, and will take a table passed in directly as their data source, only pulling in the options currently visible to the user. In those cases, pass the table directly to the component, otherwise you will fetch the entire column of data unnecessarily. + +## Tab switcher with `use_column_data` + +In the example below, use the `use_column_data` hook to get all the options for the `Exchange` columns, then build tabs for each option. When you click on a tab, the table is filtered to show only the rows where the `Exchange` column matches the tab name. + +```python +from deephaven import ui +from deephaven.table import Table +from deephaven.plot import express as dx + + +@ui.component +def ui_table_tabs(source: Table, column_name: str): + table_options = ui.use_memo( + lambda: source.select_distinct("Exchange"), [source, column_name] + ) + exchanges = ui.use_column_data(table_options) + + return ui.tabs( + *[ + ui.tab(source.where(f"{column_name}=`{exchange}`"), title=exchange) + for exchange in exchanges + ] + ) + + +_stocks = dx.data.stocks() +table_tabs = ui_table_tabs(_stocks, "Exchange") +``` ## API Reference From 7d25445858f59c334209ebe536752eea9e0a9ca3 Mon Sep 17 00:00:00 2001 From: mikebender Date: Tue, 19 Nov 2024 09:13:53 -0500 Subject: [PATCH 11/11] Rename hooks README to overview.md --- plugins/ui/docs/hooks/{README.md => overview.md} | 2 +- plugins/ui/docs/sidebar.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename plugins/ui/docs/hooks/{README.md => overview.md} (98%) diff --git a/plugins/ui/docs/hooks/README.md b/plugins/ui/docs/hooks/overview.md similarity index 98% rename from plugins/ui/docs/hooks/README.md rename to plugins/ui/docs/hooks/overview.md index 387bcbb43..39d302f18 100644 --- a/plugins/ui/docs/hooks/README.md +++ b/plugins/ui/docs/hooks/overview.md @@ -31,7 +31,7 @@ Below are all the built-in hooks that deephaven.ui provides. _State_ lets a component remember some data between renders and trigger a re-render when the data changes. For example, a counter component might use state to keep track of the current count. -The [`use_state`](use_state.md) hook adds state to a component. +The [`use_state`](use_state.md) hook adds state to a component. ### Ref hooks diff --git a/plugins/ui/docs/sidebar.json b/plugins/ui/docs/sidebar.json index e3c9a2202..a6ec9eee1 100644 --- a/plugins/ui/docs/sidebar.json +++ b/plugins/ui/docs/sidebar.json @@ -148,7 +148,7 @@ "items": [ { "label": "Overview", - "path": "hooks/README.md" + "path": "hooks/overview.md" }, { "label": "use_boolean",