diff --git a/src/React/CHANGELOG.md b/src/React/CHANGELOG.md index 77b48ddca31..c9c5c066314 100644 --- a/src/React/CHANGELOG.md +++ b/src/React/CHANGELOG.md @@ -1,5 +1,10 @@ # CHANGELOG +## 2.21.0 + +- Add `permanent` option to the `react_component` Twig function, to prevent the + _unmounting_ when the component is deconnected and immediately re-connected. + ## 2.13.2 - Revert "Change JavaScript package to `type: module`" diff --git a/src/React/assets/dist/render_controller.d.ts b/src/React/assets/dist/render_controller.d.ts index fc7b1dd4371..8f6dbd18037 100644 --- a/src/React/assets/dist/render_controller.d.ts +++ b/src/React/assets/dist/render_controller.d.ts @@ -3,9 +3,14 @@ import { Controller } from '@hotwired/stimulus'; export default class extends Controller { readonly componentValue?: string; readonly propsValue?: object; + readonly permanentValue: boolean; static values: { component: StringConstructor; props: ObjectConstructor; + permanent: { + type: BooleanConstructor; + default: boolean; + }; }; connect(): void; disconnect(): void; diff --git a/src/React/assets/dist/render_controller.js b/src/React/assets/dist/render_controller.js index 5b8f9fb8e7c..c66a32044ed 100644 --- a/src/React/assets/dist/render_controller.js +++ b/src/React/assets/dist/render_controller.js @@ -54,6 +54,9 @@ class default_1 extends Controller { }); } disconnect() { + if (this.permanentValue) { + return; + } this.element.root.unmount(); this.dispatchEvent('unmount', { component: this.componentValue, @@ -74,6 +77,7 @@ class default_1 extends Controller { default_1.values = { component: String, props: Object, + permanent: { type: Boolean, default: false }, }; export { default_1 as default }; diff --git a/src/React/assets/src/render_controller.ts b/src/React/assets/src/render_controller.ts index 595b5a6ae22..b35d049956b 100644 --- a/src/React/assets/src/render_controller.ts +++ b/src/React/assets/src/render_controller.ts @@ -14,17 +14,17 @@ import { Controller } from '@hotwired/stimulus'; export default class extends Controller { declare readonly componentValue?: string; declare readonly propsValue?: object; + declare readonly permanentValue: boolean; static values = { component: String, props: Object, + permanent: { type: Boolean, default: false }, }; connect() { const props = this.propsValue ? this.propsValue : null; - this.dispatchEvent('connect', { component: this.componentValue, props: props }); - if (!this.componentValue) { throw new Error('No component specified.'); } @@ -40,6 +40,12 @@ export default class extends Controller { } disconnect() { + if (this.permanentValue) { + // Prevent unmounting the component if the controller is permanent + // (no render is allowed after unmounting) + return; + } + (this.element as any).root.unmount(); this.dispatchEvent('unmount', { component: this.componentValue, diff --git a/src/React/doc/index.rst b/src/React/doc/index.rst index 06a2b2854fe..96e16e0aa1e 100644 --- a/src/React/doc/index.rst +++ b/src/React/doc/index.rst @@ -2,12 +2,14 @@ Symfony UX React ================ Symfony UX React is a Symfony bundle integrating `React`_ in -Symfony applications. It is part of `the Symfony UX initiative`_. +Symfony applications. It is part of the `Symfony UX initiative`_. React is a JavaScript library for building user interfaces. Symfony UX React provides tools to render React components from Twig, handling rendering and data transfers. +You can see a live example of this integration on the `Symfony UX React demo`_. + Symfony UX React supports React 18+. Installation @@ -41,6 +43,9 @@ React components. Usage ----- +Register components +~~~~~~~~~~~~~~~~~~~ + The Flex recipe will have already added the ``registerReactControllerComponents()`` code to your ``assets/app.js`` file: @@ -55,7 +60,11 @@ This will load all React components located in the ``assets/react/controllers`` directory. These are known as **React controller components**: top-level components that are meant to be rendered from Twig. -You can render any React controller component in Twig using the ``react_component()``. +Render in Twig +~~~~~~~~~~~~~~ + +You can render any React controller component in your Twig templates, using the +``react_component()`` function. For example: @@ -82,6 +91,31 @@ For example:
{% endblock %} +Permanent components +~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.21 + + The ability to mark a component ``permanent`` was added in UX React 2.21. + +The controller responsible to render the React components can be configured +to keep the React component mounted when the root element is removed from +the DOM, using the ``permanent`` option. + +This is particularly useful when the root element of a component is moved around +in the DOM or is removed and immediately re-added to the DOM (e.g. when using +`Turbo`_ and its `data-turbo-permanent` attribute). + +.. code-block:: html+twig + + {# templates/home.html.twig #} + {% extends 'base.html.twig' %} + + {# The React component will stay mounted if the div is moved in the DOM #} +