From a9454fe535b8b48d7800e60f575fd1a10539b3e8 Mon Sep 17 00:00:00 2001 From: AlainaFaisal Date: Thu, 22 Aug 2024 10:22:08 +0300 Subject: [PATCH] Document how to wrap a field React component into Flow component (#3600) * Update PR check configs from master * Initial Draft * Initial Draft 2 * Update articles/flow/integrations/react.adoc Co-authored-by: caalador * Update articles/flow/integrations/react.adoc Co-authored-by: caalador * Update articles/flow/integrations/react.adoc Co-authored-by: caalador * Update articles/flow/integrations/react.adoc Co-authored-by: caalador * Update articles/flow/integrations/react.adoc Co-authored-by: caalador * Update articles/flow/integrations/react.adoc Co-authored-by: caalador * Update articles/flow/integrations/react.adoc Co-authored-by: caalador * Delete .github/workflows/alex.yml * Update articles/flow/integrations/react.adoc Co-authored-by: caalador * Update articles/flow/integrations/react.adoc Co-authored-by: caalador * Update articles/flow/integrations/react.adoc Co-authored-by: caalador --------- Co-authored-by: Jouni Koivuviita Co-authored-by: caalador --- articles/flow/integrations/react.adoc | 81 +++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/articles/flow/integrations/react.adoc b/articles/flow/integrations/react.adoc index a12326679e..43f2991855 100644 --- a/articles/flow/integrations/react.adoc +++ b/articles/flow/integrations/react.adoc @@ -208,3 +208,84 @@ class ReactRouterLayoutElement extends ReactAdapterElement { customElements.define('react-router-layout', ReactRouterLayoutElement); ---- + +[[wrap-react-component]] +== Wrapping a React Component Into a Flow Component + +When integrating React components into Vaadin applications, one common requirement is to enable these components to participate in Vaadin's data binding and form handling. +This can be accomplished by wrapping the React component in a Vaadin component that extends `AbstractSinglePropertyField`. +This allows the React component to be used like any other field in Vaadin, making it compatible with the `Binder` API. + +This integration process involves two main parts: + - creating a Java class for the server-side adapter component + - developing a client-side adapter using TypeScript and React. +Next this process is demonstrated using a simple React text input component as an example. + +=== Example Implementation: + +=== Create the Client-Side React Component +First, define your React component. For this example, assume a simple text input component. +[source,jsx] +---- +// File: frontend/react-text-input.tsx + +import React, { useState } from 'react'; +import {ReactAdapterElement, type RenderHooks} from "Frontend/generated/flow/ReactAdapter"; + +class ReactTextInputElement extends ReactAdapterElement { + constructor() { + super(); + } + + protected override render(hooks: RenderHooks): React.ReactElement | null { + const [value, setValue] = hooks.useState("value"); + + const handleChange = (event: React.ChangeEvent) => { + setValue(event.target.value); + this.dispatchEvent(new CustomEvent('value-changed', { detail: { value: event.target.value } })); + }; + + return ( +
+ + {value?.length} characters +
+ ); + } +} + +customElements.define('react-text-input', ReactTextInputElement); +---- + +=== Server-Side Vaadin Component Wrapping the React Component +Next, create a Vaadin component that wraps the React component and extends `AbstractSinglePropertyField`. + +[source,java] +---- +// Package: com.example.application.ui + +import com.vaadin.flow.component.Tag; +import com.vaadin.flow.component.dependency.JsModule; +import com.vaadin.flow.component.AbstractSinglePropertyField; + +@Tag("react-text-input") +@JsModule("./react-text-input.tsx") +public class ReactTextField extends AbstractSinglePropertyField { + public ReactTextField() { + super("value", "", false); + } +} +---- + +=== Using the React Component in a Vaadin Form +Now, you can use `ReactTextField` like any other Vaadin component within a form: + +[source,java] +---- +Binder binder = new Binder<>(Person.class); +ReactTextField reactTextField = new ReactTextField(); + +binder.forField(reactTextField).bind(Person::getName, Person::setName); + +add(reactTextField); +---- \ No newline at end of file