-
Notifications
You must be signed in to change notification settings - Fork 33
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
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
Minimal example that incorporates react components #97
Comments
TL;DR - Totally possible today to create and use React widgets with anywidget! I just haven't added to the documentation because 1.) it requires a bit of boilerplate and 2.) I'm working on a way to support react/other frameworks with less boilerplate. Thanks for the suggestion! I agree that it would be great to make it easier to bring React components into Jupyter widgets ecosystem. That said, I want anywidget at its core to remain agnostic to the many frontend frameworks but provide a standard for declaring widgets using web standards. For example, a React widget could be defined today with anywidget via: // index.jsx
import * as React from "https://esm.sh/react@18";
import * as ReactDOM from "https://esm.sh/react-dom@18/client";
function Square() {
return <button className="square">X</button>;
}
export function render(view) {
let root = ReactDOM.createRoot(view.el);
root.render(<Square />);
return () => root.unmount();
} but it requires using a bundler (like esbuild) to convert the JSX above into into "pure" ESM ( npx esbuild --format=esm --outfile=bundle.js index.jsx output `bundle.js`import * as React from "https://esm.sh/react@18";
import * as ReactDOM from "https://esm.sh/react-dom@18/client";
function Square() {
return /* @__PURE__ */ React.createElement("button", { className: "square" }, "X");
}
function render(view) {
let root = ReactDOM.createRoott(view.el);
root.render(/* @__PURE__ */ React.createElement(Square, null));
return () => root.unmount();
}
export {
render
}; import pathlib
import anywidget
class Square(anywidget.AnyWidget):
_esm = pathlib.Path("bundle.js") # the output of esbuild My vision for supporting frameworks like React is to reduce this kind of boilerplate, but in a way that sits on top of this ESM "core". I am currently toying with some ideas for integrating a bundler and supporting import { useModelState } from "anywidget:react/hooks";
export default function Counter() {
let [count, setCount] = useModelState("count");
return <button onClick={() => setCount(count++)} >count is {count}</button>
} |
this is so cool, your code works out of the box and correctly renders the square in the notebook, thanks a lot for this example! 🎉 Just noted two small typos
//bundle.js
import * as React from "https://esm.sh/react@18";
import * as ReactDOM from "https://esm.sh/react-dom@18/client";
function Square() {
return /* @__PURE__ */ React.createElement("button", { className: "square" }, "X");
}
function render(view) {
let root = ReactDOM.createRoot(view.el);
root.render(/* @__PURE__ */ React.createElement(Square, null));
return () => root.unmount();
}
export {
render
}; # example.ipynb
import pathlib
import anywidget
class Square(anywidget.AnyWidget):
_esm = pathlib.Path("bundle.js")
Square() I am really looking forward to where this project will lead to, and can imagine a future where many workflows that currently require lots of application switching can instead happen in only one notebook. |
Thanks for your enthusiasm and attention to detail in the code snippets I shared (and apologies for not testing locally)! For now, I'm going to pin this issue so that others who want to try out react can hopefully find it quickly. I'm hoping eventually we will have a nicer solution that should live in the docs.
Me too! Love to hear it and see what you end up coming up with. |
Thanks for the ping @kolibril13 ! Yes, I'm quite interested in this area. Actually, I've been talking to @manzt about support for React in anywidgets a few weeks ago. But I'm unsure what our conclusions were. Based on our discussion then, I did create a prototype that uses babel in the browser and using Anywidget for the HRM support, I've cobbled together: import ipyreact
import pathlib
class Demo(ipyreact.ReactWidget):
_esm = pathlib.Path("../ipyreact/test.jsx") // test.jsx
import confetti from "https://esm.sh/canvas-confetti@1.6.0";
import { useState } from "react";
export function Main() {
const [count, setCount] = useState(0);
return <button onClick={() => confetti() && setCount(count + 1)}>{count} times confetti</button>;
}; Note that I use babel to "importmap" the If there is interest in this approach in anywidget, I'm happy to discuss this further. |
This led to https://github.com/widgetti/ipyreact |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
I think there's a lot of potential in bringing react components into the ipywidget ecosystem.
This would open the door to projects like an https://www.tldraw.com/ based plot annotation tool, or interactive https://mafs.dev/ components for teaching math.
There's a minimal react example at
https://react.dev/learn/tutorial-tic-tac-toe#setup-for-the-tutorial
I don't know much about the react bundling process, therefore the question to you @manzt : would you have time and interest to investigate if it's possible to incorporate this minimal react component into an anywidget widget? That would be amazing!
And I think that other people from the community would be interested in this as well, e.g. @maartenbreddels https://discourse.jupyter.org/t/need-to-guidance-to-integrate-react-js-application-into-jupyter-extension/18477/3
The text was updated successfully, but these errors were encountered: