The basic mechanism for including Flow components in Hilla views is not new: use WebComponentExporter to create a web component that you can import to embed the component. In this case, you can reuse the Flow component that you already created in the previous step. You first need to create a simple Flow component and then a separate class that exports it as a web component.
package com.example.application;
import com.vaadin.flow.component.WebComponentExporter;
import com.vaadin.flow.component.webcomponent.WebComponent;
public class FlowExporter extends WebComponentExporter<FlowComponent> {
public FlowExporter() {
super("embed-flow");
}
@Override
protected void configureInstance(WebComponent<FlowComponent> webComponent, FlowComponent component) {
// Nothing to configure in this case
}
}
What’s new is a shorthand function for loading an exported web component from the same Vaadin server and getting that as something that can be directly rendered from JSX. You can use this to update the Hello World view to use the Flow new component.
src/main/frontend/views/@index.tsx
import { createWebComponent } from "Frontend/generated/flow/Flow";
export default function HelloWorldView() {
return (
<>
This is a Hilla view <br />
{ createWebComponent("embed-flow") }
</>
);
}
No need to memoize anything - createWebComponent returns an element for React’s virtual DOM that is thus preserved just like any other DOM element.
The way it works can easily be observed by changing the Flow component to use e.g. a TextField and then adding some logic to the React view that triggers an asynchronous re-render. In that way, you can notice that the cursor position and text selection in the text field remains over re-renders.
One simple way of doing an async re-render is with a button that updates a useState variable through setTimeout:
import { Button } from "@vaadin/react-components";
import { createWebComponent } from "Frontend/generated/flow/Flow";
import { useState } from "react";
export default function Unified() {
const [counter, setCounter] = useState(0);
return <>
<Button onClick={() => setTimeout(() => setCounter(x => x + 1), 2000)}>{counter}</Button>
{ createWebComponent("embed-flow") }
</>
}
The naming is based on React.createElement which has similar performance characteristics. But I do also see that this association isn’t 100% clear. We should reconsider the name. Might even consider turning it into a proper JSX element, i.e. <FlowComponent name="my-component" />.
Should just note that generation becomes more complicated when also taking attributes into account. The documentation is already suggesting that you create a JSX wrapper in the application.