Skip to content
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

Document how to wrap a field React component into Flow component #3600

Merged
merged 17 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/workflows/alex.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: reviewdog
AlainaFaisal marked this conversation as resolved.
Show resolved Hide resolved
on: [pull_request]
jobs:
alex:
name: runner / alex
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: reviewdog/action-alex@v1
with:
github_token: ${{ secrets.github_token }}
# Change reviewdog reporter if you need [github-pr-check,github-check,github-pr-review].
reporter: github-pr-review
# Change reporter level if you need.
# GitHub Status Check won't become failure with warning.
level: warning
77 changes: 77 additions & 0 deletions articles/flow/integrations/react.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,80 @@

customElements.define('react-router-layout', ReactRouterLayoutElement);
----

[[wrap-react-component]]
== Wrapping a React component into Flow component

Check warning on line 213 in articles/flow/integrations/react.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vaadin.HeadingCase] 'Wrapping a React component into Flow component' should be in title case. Raw Output: {"message": "[Vaadin.HeadingCase] 'Wrapping a React component into Flow component' should be in title case.", "location": {"path": "articles/flow/integrations/react.adoc", "range": {"start": {"line": 213, "column": 4}}}, "severity": "WARNING"}
AlainaFaisal marked this conversation as resolved.
Show resolved Hide resolved

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 setup allows the React component to be used just like any other field in Vaadin, making it compatible with `Binder` API.

Check warning on line 215 in articles/flow/integrations/react.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vaadin.JustSimply] Avoid using 'just'. It may be insensitive. Raw Output: {"message": "[Vaadin.JustSimply] Avoid using 'just'. It may be insensitive.", "location": {"path": "articles/flow/integrations/react.adoc", "range": {"start": {"line": 215, "column": 345}}}, "severity": "WARNING"}
AlainaFaisal marked this conversation as resolved.
Show resolved Hide resolved

This integration process involves two main parts: creating a Java class for the server-side adapter component, and developing a client-side adapter using TypeScript and React. Below, we demonstrate this process using a simple React text input component as an example.

Check warning on line 217 in articles/flow/integrations/react.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vaadin.We] Try to avoid using first-person plural like 'we'. Raw Output: {"message": "[Vaadin.We] Try to avoid using first-person plural like 'we'.", "location": {"path": "articles/flow/integrations/react.adoc", "range": {"start": {"line": 217, "column": 184}}}, "severity": "WARNING"}
AlainaFaisal marked this conversation as resolved.
Show resolved Hide resolved

=== 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 ReactDOM from 'react-dom';
AlainaFaisal marked this conversation as resolved.
Show resolved Hide resolved
import { ReactAdapterElement, RenderHooks } from '@vaadin/flow-frontend/ReactAdapterElement';

class ReactTextInputElement extends ReactAdapterElement {
constructor() {
super();
}
AlainaFaisal marked this conversation as resolved.
Show resolved Hide resolved

protected override render(hooks: RenderHooks): React.ReactElement | null {
const [value, setValue] = hooks.useState<string>("value");

const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setValue(event.target.value);
this.dispatchEvent(new CustomEvent('value-changed', { detail: { value: event.target.value } }));
};

return (
<div>
<input type="text" value={value} onChange={handleChange} />
<span>{value.length} characters</span>
AlainaFaisal marked this conversation as resolved.
Show resolved Hide resolved
</div>
);
}
}
AlainaFaisal marked this conversation as resolved.
Show resolved Hide resolved
----

=== 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.textfield.AbstractSinglePropertyField;
AlainaFaisal marked this conversation as resolved.
Show resolved Hide resolved

@Tag("react-text-input")
@JsModule("./src/react-text-input.js")
public class ReactTextField extends AbstractSinglePropertyField<ReactTextField, String> {
public ReactTextField() {
super("value", "", false);
// Synchronize the "value" property on the React side with the Java side whenever the "value-changed" event is fired
getElement().synchronizeProperty("value", "value-changed");
vursen marked this conversation as resolved.
Show resolved Hide resolved
}
}
----

=== Using the React Component in a Vaadin Form
Now, you can use `ReactTextField` just like any other Vaadin component within a form:

Check warning on line 277 in articles/flow/integrations/react.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vaadin.JustSimply] Avoid using 'just'. It may be insensitive. Raw Output: {"message": "[Vaadin.JustSimply] Avoid using 'just'. It may be insensitive.", "location": {"path": "articles/flow/integrations/react.adoc", "range": {"start": {"line": 277, "column": 35}}}, "severity": "WARNING"}
AlainaFaisal marked this conversation as resolved.
Show resolved Hide resolved

[source,java]
----
Binder<Person> binder = new Binder<>(Person.class);
ReactTextField reactTextField = new ReactTextField();

binder.forField(reactTextField).bind(Person::getName, Person::setName);

add(reactTextField);
----
Loading