Skip to content

Commit c8e1a1d

Browse files
committed
allow jupyter widgets to be used in reactpy components
1 parent 3900cb2 commit c8e1a1d

10 files changed

+317
-2167
lines changed

Diff for: notebooks/introduction.ipynb

+53-21
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@
44
"cell_type": "markdown",
55
"metadata": {},
66
"source": [
7-
"# What is ReactPy?\n",
7+
"<img src=\"https://raw.githubusercontent.com/reactive-python/reactpy/main/branding/svg/reactpy-logo-landscape.svg\" alt=\"ReactPy Logo\" style=\"min-width: 300px; width: 35%\" />\n",
88
"\n",
9-
"ReactPy connects your Python web framework of choice to a ReactJS frontend, allowing you to create **interactive websites without needing JavaScript!**\n",
9+
"---\n",
1010
"\n",
11-
"Following ReactJS styling, web elements are combined into [reusable \"components\"](https://reactpy.dev/docs/guides/creating-interfaces/your-first-components/index.html#parametrizing-components). These components can utilize [hooks](https://reactpy.dev/docs/reference/hooks-api.html) and [events](https://reactpy.dev/docs/guides/adding-interactivity/responding-to-events/index.html#async-event-handlers) to create infinitely complex web pages.\n",
11+
"[ReactPy](https://reactpy.dev/) is a library for building user interfaces in Python without Javascript. ReactPy interfaces are made from components which look and behave similarly to those found in [ReactJS](https://reactjs.org/). Designed with simplicity in mind, ReactPy can be used by those without web development experience while also being powerful enough to grow with your ambitions.\n",
1212
"\n",
13-
"When needed, ReactPy can [use components directly from NPM](https://reactpy.dev/docs/guides/escape-hatches/javascript-components.html#dynamically-loaded-components). For additional flexibility, components can also be [fully developed in JavaScript](https://reactpy.dev/docs/guides/escape-hatches/javascript-components.html#custom-javascript-components).\n",
1413
"\n",
1514
"\n",
1615
"# Getting Started\n",
@@ -60,7 +59,7 @@
6059
},
6160
"outputs": [],
6261
"source": [
63-
"from reactpy import component, html, run\n",
62+
"from reactpy import component, html\n",
6463
"\n",
6564
"\n",
6665
"@component\n",
@@ -186,7 +185,29 @@
186185
"source": [
187186
"# Using ReactPy With Jupyter Widgets\n",
188187
"\n",
189-
"While you can use ReactPy components independently, it may also be useful to integrate them with the rest of the Jupyter Widget ecosystem. Let's consider a ReactPy component that responds to and displays changes from an `ipywidgets.IntSlider`. The ReactPy component will need to accept an `IntSlider` instance as one of its arguments, declare state that will track the slider's value, and register a lister that will update that state via the slider's `IntSlider.observe()` method using an [\"effect\"](https://reactpy.dev/docs/reference/hooks-api.html#use-effect):"
188+
"It's possible to use Jupyter Widgets in ReactPy components if you convert them first using `reactpy_jupyter.from_widget`."
189+
]
190+
},
191+
{
192+
"cell_type": "code",
193+
"execution_count": null,
194+
"metadata": {},
195+
"outputs": [],
196+
"source": [
197+
"from reactpy_jupyter import from_widget\n",
198+
"from ipywidgets import IntSlider\n",
199+
"\n",
200+
"slider_widget = IntSlider()\n",
201+
"slider_component = from_widget(slider_widget)\n",
202+
"\n",
203+
"slider_component"
204+
]
205+
},
206+
{
207+
"cell_type": "markdown",
208+
"metadata": {},
209+
"source": [
210+
"Let's consider a ReactPy component that responds to and displays changes from an `ipywidgets.IntSlider`. The ReactPy component will need to accept an `IntSlider` instance as one of its arguments, convert it to a component with `from_widget`, declare state that will track the slider's value, and register a lister that will update that state via the slider's `IntSlider.observe()` method using an [\"effect\"](https://reactpy.dev/docs/reference/hooks-api.html#use-effect):"
190211
]
191212
},
192213
{
@@ -198,10 +219,12 @@
198219
"outputs": [],
199220
"source": [
200221
"from reactpy import use_effect\n",
222+
"from reactpy_jupyter import from_widget\n",
201223
"\n",
202224
"\n",
203225
"@component\n",
204226
"def SliderObserver(slider):\n",
227+
" slider_component = from_widget(slider)\n",
205228
" value, set_value = use_state(0)\n",
206229
"\n",
207230
" @use_effect\n",
@@ -214,14 +237,14 @@
214237
" # unobserve the slider's value if this component is no longer displayed\n",
215238
" return lambda: slider.unobserve(handle_change, \"value\")\n",
216239
"\n",
217-
" return html.p(f\"ReactPy observes the value to be: \", value)"
240+
" return html.div(slider_component, html.p(f\"ReactPy observes the value to be: \", value))"
218241
]
219242
},
220243
{
221244
"cell_type": "markdown",
222245
"metadata": {},
223246
"source": [
224-
"Now you'll need to display the `SliderObserver` component as well as an `IntSlider` widget. To do this, you'll want wrap the component in a `reactpy_jupyter.LayoutWidget` instance before using it alongside other Jupyter Widgets. Specifically, you'll be displaying the `SliderObserver` and `IntSlider` in a `Box`:\n"
247+
"Now you need to pass the `SliderObserver` component an `IntSlider` widget and display it.\n"
225248
]
226249
},
227250
{
@@ -232,20 +255,16 @@
232255
},
233256
"outputs": [],
234257
"source": [
235-
"from ipywidgets import Box, IntSlider\n",
236-
"from reactpy_jupyter import LayoutWidget\n",
237-
"\n",
238-
"slider = IntSlider(readout=False)\n",
239-
"slider_observer = LayoutWidget(SliderObserver(slider))\n",
258+
"from ipywidgets import IntSlider\n",
240259
"\n",
241-
"Box([slider, slider_observer])"
260+
"SliderObserver(IntSlider(readout=False))"
242261
]
243262
},
244263
{
245264
"cell_type": "markdown",
246265
"metadata": {},
247266
"source": [
248-
"If it becomes painful to wrap every ReactPy component in a `LayoutWidget` you can create an alternate `LayoutWidget` constructor using `reactpy_jupyter.widgetize`:"
267+
"You can also include ReactPy components within Jupyter Widgets using `reactpy_jupyter.to_widget`"
249268
]
250269
},
251270
{
@@ -256,21 +275,34 @@
256275
},
257276
"outputs": [],
258277
"source": [
259-
"from reactpy_jupyter import widgetize\n",
260-
"\n",
261-
"SliderObserverWidget = widgetize(SliderObserver)\n",
278+
"from ipywidgets import Box\n",
279+
"from reactpy_jupyter import to_widget\n",
262280
"\n",
263281
"slider = IntSlider(readout=False)\n",
264-
"slider_observer = SliderObserverWidget(slider)\n",
282+
"slider_observer_widget = to_widget(SliderObserver(slider))\n",
265283
"\n",
266-
"Box([slider, slider_observer])"
284+
"Box([slider, slider_observer_widget])"
267285
]
268286
},
269287
{
270288
"cell_type": "markdown",
271289
"metadata": {},
272290
"source": [
273-
"It's worth noting that, while ReactPy can be used with Jupyter Widgets, the reverse is not true. That is, **you cannot use a Jupyter Widget inside a ReactPy component**. If this is a capability you would find useful, please [start a discussion](https://github.com/reactive-python/reactpy/discussions). The ReactPy team would be very interested to hear how allowing Jupyter Widgets to be used with ReactPy could facilitate your work."
291+
"If it becomes painful to convert every ReactPy component to a jupyter widget you can create an alternate widget constructor:"
292+
]
293+
},
294+
{
295+
"cell_type": "code",
296+
"execution_count": null,
297+
"metadata": {},
298+
"outputs": [],
299+
"source": [
300+
"slider = IntSlider(readout=False)\n",
301+
"slider_observer_constructor = to_widget(SliderObserver)\n",
302+
"observer_1 = slider_observer_constructor(slider)\n",
303+
"observer_2 = slider_observer_constructor(slider)\n",
304+
"\n",
305+
"Box([observer_1, observer_2])"
274306
]
275307
},
276308
{

0 commit comments

Comments
 (0)