From 4df476cdaad9c88e83731c7ac4e3c5943816e3df Mon Sep 17 00:00:00 2001 From: Anuj Singla Date: Sun, 24 Mar 2024 15:10:56 +0530 Subject: [PATCH] docs: update react integration (#2641) * docs: update documentation for React integration with components * docs: update documentation for React integration with components * docs: update documentation for React integration with components * docs: update documentation for React integration with components * docs: update documentation for React integration with components * docs: update documentation for React integration with components * docs: update documentation for React integration with components * docs: update documentation for React integration with components * docs: update documentation for React integration with components * docs: update documentation for React integration with components * docs: update documentation for React integration with components * docs: update documentation for React integration with components * docs: update documentation for React integration with components * docs: revise react post * docs: fix layout --------- Co-authored-by: Anuj Singla Co-authored-by: Benny Powers --- docs/framework-integration/react.md | 601 ++++++++++++++-------------- 1 file changed, 299 insertions(+), 302 deletions(-) diff --git a/docs/framework-integration/react.md b/docs/framework-integration/react.md index eafef24020..fc2d3f7ab6 100644 --- a/docs/framework-integration/react.md +++ b/docs/framework-integration/react.md @@ -9,357 +9,354 @@ tags:

{{ title }}

-{% band header="Using PatternFly Elements in your React app" %} - To get web components to work with React it’s pretty easy and straightforward. If you’d like to follow along, - go ahead and [create a new React CodeSandbox on codesandbox.io](https://codesandbox.io/s/new). - The React sandbox uses [create-react-app](https://github.com/facebook/create-react-app) to scaffold an app and you can - view your changes in real-time right in the web app. With CodeSandbox, you can also add any npm dependency with - just a few button clicks. If you want to run this app locally, you can - [clone the repository on - GitHub](https://github.com/kylebuch8/patternfly-elements-with-react). - - “Using PatternFly Elements in your React App” is broken down into four sections: - - Initial setup - - Adding PatternFly Elements - - Interacting with our web components API - - Adding icing on the cake - - Each section will show you exactly what you need to do with code snippets and an accompanying CodeSandbox that you can edit or fork. -{% endband %} - -{% band header="Initial setup" %} - Import React and ReactDOM at the top of the `index.js` file in the `/src/` directory. +
+ + ## Using PatternFly Elements in your React app + + PatternFly Elements ships with React wrappers for each web component. These + wrappers make working with web components + withing react JSX files more convenient. In this post, we'll create a simple + React app using PatternFly elements, and demonstrate how state can be shared + between react components and custom elements. + + If you'd like to skip right to the code, you can check out the finished app on + [Codesandbox][codesandbox]. For a more advanced example, take a look at [Anuj + Singla's example repo on Github][repo], which demonstrates commit-by-commit + how you can migrate a react app to all web-components. + +
+ +
+ + ## Why Does React Need Special Treatment? + PatternFly elements are Web components: they're based on a set of web platform + APIs that help to create reusable and encapsulated UI elements. Those standards + consist of Custom Elements, Shadow DOM, and HTML Templates. + + React is a JavaScript framework that uses a virtual DOM to optimize updates and + minimize the number of changes that need to be made to the actual DOM. This + virtual DOM is only a conceptual representation of what the react app does in + the browser, it doesn't and can't line up perfectly with the real DOM. In + practically all cases, React applications are written using the non-standard JSX + language, which must be compiled to JavaScript in order to run on the user's + browser. Although JSX looks superficially similar to HTML, it is in fact a + completely separate language. This visual similarity often leads to confusion + among developers who may not be familiar with the many subtle differences + between JSX and HTML and the many "gotchas" which arise from react's use of a + virtual DOM. + + React needs special treatment when integrating with web components because of + it's reliance on virtual DOM and JSX. Of all the major JavaScript frameworks, + react is currently the only one without proper support for HTML and the DOM + standards, as documented at the [Custom Elements Everywhere][cee] project, which + runs a suite of tests against each framework to identify interoperability issues + and highlight potential fixes already implemented in other frameworks. + + Multiple libraries are available to fill the gap between React and web + components, like [@lit/react][llr]. PatternFly Elements uses this library to + create the react wrapper components. + + ### Comparing React and Web Components + There are some important differences between React and HTML which developers + should be aware of when working with web components in react apps: + + #### Virtual DOM vs. Shadow DOM + Web components use shadow DOM to encapsulate styles and functionality within + the private rendering context of a custom element. Without shadow DOM, special + care is needed to ensure that styles and DOM IDs do not conflict. + + React uses a virtual DOM to batch and diff changes to the real DOM. Because + the virtual DOM is separate from the browser's true representation of the + document, React requires developers to work with the virtual DOM concepts + *props* and [*synthetic events*][synthevent], rather than DOM properties, HTML + attributes, and JavaScript events. + + Web components use these standard DOM and HTML APIs to manage their own state + and communicate with other components. Because of React's special virtual DOM + and JSX syntax, developers need to employ workarounds to listen for events + from web components and set DOM properties or HTML attributes on them. This is + the primary purpose of [`@lit/react`][llr]. + + #### Component Lifecycle + React components can implement [lifecycle methods][react-lifecycle] + like `componentDidMount`, `componentDidUpdate`, etc., or use "hooks" to manage + their lifecycle. Custom elements have a set of standard [lifecycle + callbacks][ce-lifecycle] like `connectedCallback` and `disconnectedCallback`. + Depending on the library used to write the web component, there may be + additional lifecycle methods, for example `LitElement` has an `updated` + callback. + + #### Reactivity + Not every DOM property or HTML attribute change causes a web component + re-render, it depends on whether the authors of that web component wrote it + that way. For example, a web component author can choose to add a reactive + attribute/property called `disabled` which causes a rerender every time it + changes, or they can choose not to re-render when it changes. It's important + to read the documentation for elements that you use in order to understand + which public APIs the authors intended you to use. + +
+ +
+ + ## Initial setup + We'll bootstrap our react app using [Vite][vite]. It's possible to use other + tools for this, but that is out of the scope of this tutorial. - ```js - import React from 'react'; - import ReactDOM from 'react-dom'; + ```bash + npm create vite@latest ``` -{% endband %} + This command will ask you to provide the project name, framework, and variant. -{% band header="Adding PatternFly Elements" %} - With the setup complete, let’s add a couple of PatternFly Elements web components to our application to make sure everything is hooked up properly. - We’re going to add a card ([pf-card](/components/card)). - Later, we’ll add an accordion ([pf-accordion](/components/accordion)) and some CSS to help with our layout ([pf-layouts](/layout)). +
- Once again, if we were building this app locally, we’d install our dependencies from npm using yarn. +
+ + ## Adding PatternFly Elements + With the setup complete, You need to install `@patternfly/elements` and the + `@lit/react` library. ```bash - yarn add @patternfly/elements + npm install @lit-labs/react @patternfly/elements ``` - But if you’re using CodeSandbox, just search for "@patternfly/pf-card" - In our `index.js` file in the `/src/` directory, let’s add the import statements for our components to the top of the file. + ### Button and Card + + Let's import the various components we'll use in our `App.tsx` file in the + `/src/` directory. ```js - import React from "react"; - import ReactDOM from "react-dom"; - import "@patternfly/elements/pf-card/pf-card.js"; - import "./styles.css"; + import { useState } from "react"; + + import { Button } from "@patternfly/elements/react/pf-button/pf-button.js"; + import { Card } from "@patternfly/elements/react/pf-card/pf-card.js"; + import { Switch } from "@patternfly/elements/react/pf-switch/pf-switch.js"; + import { Popover } from "@patternfly/elements/react/pf-popover/pf-popover.js"; + import { Tooltip } from "@patternfly/elements/react/pf-tooltip/pf-tooltip.js"; + + import "./App.css"; ``` - Let’s add some simple markup in the `App` function in the `index.js` file to see that our pf-card is working. + Let’s use [`pf-button`][pf-button] and [`pf-card`][pf-card] component in the + `App` function in the `App.tsx` file to see that our Card and Button are + working. We are updating the local state and showing it in the UI after + clicking the button. ```js function App() { + const [count, setCount] = useState(0); + return ( -
-

PatternFly Elements with React

- - From https://picsum.photos/ -

This is the light pf-card and a link.

-

- Leverage agile frameworks to provide a robust synopsis for high level - overviews. Iterative approaches to corporate strategy foster collaborative - thinking to further the overall value proposition. -

-

- Organically grow the holistic world view of disruptive innovation via - workplace diversity and empowerment. -

- Learn more -
-
+ +

React + PatternFly Elements

+
count is {count}
+ +
); } ``` - Below is the accompanying CodeSandbox to see that our initial setup is correct and that we’ve successfully added our web components to our app. -{% endband %} + ### Switch -{% band %} - -{% endband %} - -{% band header="Interacting with our web components API" %} - After adding our accordion, let’s say that we’d like to have the first panel of the accordion - open up after the page loads. To work with the accordion, there are a few things that we need to - hook up. - - > 👉 **Note**: React 18@experimental provides support for HTML, so the `useEffect`/`useRef` - > workaround is no longer needed for property setting and event listeners - - First, let’s import `useRef` and `useEffect`. + const onMousehide = () => { + popoverRef.current?.hide(); + }; - ```js - import React, { useRef, useEffect } from "react"; + return ( + +

React + PatternFly Elements

+
count is {count}
+ +

+ + show tooltip on mouse over + +

+

+ + + popover + +

+ + + +
+ ); + } ``` - Now let’s create a React Ref so we can work with the pf-accordion DOM API. To learn more about - Refs and the DOM in React, - [check out their documentation](https://reactjs.org/docs/refs-and-the-dom.html). We’ll start by - creating a new ref inside our `App` function. +
- ```js - const accordion = useRef(); - ``` +
- We'll add a `useEffect` callback and call the `toggle` method on the ref's current element - (our ``), so we can open the first panel of the accordion when the page loads. + ## Codesandbox example + - ```js - useEffect(() => { - accordion.current.toggle(0); - }); - ``` + View and edit the source on [Codesandbox][codesandbox]. - Next, let’s add all of our markup from the `App` function we had previously to our `return` method. - We’ll also want to add a ref attribute to the opening tag of pf-accordion and set it equal to `{accordion}`. +
- ```js - function App() { - const accordion = useRef(); +
- useEffect(() => { - accordion.current.toggle(0); - }); + ## Recap + Let’s recap what we did. - return ( -
-

PatternFly Elements with React

-
- - From https://picsum.photos/ -

- This is the light pf-card and a link. -

-

- Leverage agile frameworks to provide a robust synopsis for high - level overviews. Iterative approaches to corporate strategy foster - collaborative thinking to further the overall value proposition. -

-

- Organically grow the holistic world view of disruptive innovation - via workplace diversity and empowerment. -

- Learn more -
-
-
- - -

Why do wizards need money if they could just create it?

-
- -

- There is legislation that decides what you can conjure and what - you can not. Because things that you conjure out of thin air - will not last, it is illegal in the wizarding world. -

-
- -

Why doesn't Harry have a portrait of his parents?

-
- -

- The characters in the portraits are not actually - ghosts. They mainly are there just to repeat common phrases or - serve as a general - - representation of the individual - {" "} - they depict. A portrait of his parents would not be of much help - to Harry. -

-
- -

- Why is Harry considered a half-blood if both of his parents - could use magic? -

-
- -

- Because Harry's grandparents were not able to do magic. This is - generally frowned upon by those who consider themselves pure, - such as the Malfoy's or other antagonists. -

-
- -

Is Hogwarts the only wizarding school?

-
- -

- No! It has been revealed that there are actually 11 long - established and prestigious schools around the globe. These - include Castelobruxo in the rainforest of Brazil, Durmstrang - Institute (whereas nobody is certain of it’s whereabouts), and - Ilvermorny, right here in the United States. -

-
- -

Where do the main characters work as adults?

-
- -

- Harry and Hermione are at the Ministry: he ends up leading the - Auror department. Ron helps George at the joke shop and does - very well. Ginny becomes a professional Quidditch player and - then sportswriter for the Daily Prophet. -

-

- - Read more about the characters - -

-
-
-
-
- ); - } - ``` + 1. Initial setup: Created React project (TypeScript + Vite). + 2. Added PatternFly Elements: Installed @lit-labs/react and @patternfly/elements libraries. + 3. Added Button, Switch, Card, Tooltip, and Popover components: + - Enable/disable a button by clicking the switch button. + - Show tooltip text on mouseover. + - Created a reference to the popover to open the popover on the mouse-over of the button. + +
- Now, when the page loads, the accordion will have the first panel opened. Below is the accompanying CodeSandbox. +
- -{% endband %} + ## Wrap up -{% band %} - I realize that may have been a lot. So let’s recap what we did. + So there you have it. We’ve added web components to our React app and gained + the benefits of using portable, pre-made components that can also be used in + other frameworks like Angular and Vue. If your app is written in Angular or Vue, + check out our other two posts: Using [PatternFly Elements in your Angular + App][inng] and Using [PatternFly Elements in your Vue App][invue]. - 1. Initial Setup: Added the web component polyfills - 2. Adding PatternFly Elements (web components): Added the following web components as dependencies in our app: pf-card, and pf-accordion - 3. Adding PatternFly Elements (web components): Imported the web components into our `index.js` file - 4. Adding PatternFly Elements (web components): Added the markup for our components in `index.js` - 5. Interacting with our web components API: Created a reference to the accordion so we could open the first panel after the page loads -{% endband %} +
-{% band header="Wrap up" %} - So there you have it. We’ve added web components to our React app and gained the benefits of using portable, pre-made components that can also be used in other frameworks like Angular and Vue. If your app is written in Angular or Vue, check out our other two posts: “Using PatternFly Elements in your Angular App” and “Using PatternFly Elements in your Vue App.” -{% endband %} +[codesandbox]: https://codesandbox.io/p/devbox/pfe-react-wrappers-3g6x6r?file=%2Fsrc%2FApp.tsx +[repo]: https://github.com/anujsingla/react-patternfly-elements +[cee]: https://custom-elements-everywhere.com/ +[llr]: https://github.com/lit/lit/tree/main/packages/react#litreact +[synthevent]: https://react.dev/reference/react-dom/components/common#react-event-object +[ce-lifecycle]: https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks +[react-lifecycle]: https://legacy.reactjs.org/docs/state-and-lifecycle.html +[vite]: https://vitejs.dev/guide/#scaffolding-your-first-vite-project +[pf-button]: https://patternflyelements.org/components/button/ +[pf-card]: https://patternflyelements.org/components/card/ +[pf-switch]: https://patternflyelements.org/components/switch/ +[pf-tooltip]: https://patternflyelements.org/components/tooltip/ +[pf-popover]: https://patternflyelements.org/components/popover/ +[inng]: https://medium.com/patternfly-elements/using-patternfly-elements-web-components-in-your-angular-app-4b18b1c9c363 +[invue]: https://patternflyelements.org/framework-integration/vue/