· 5 min read

Du React avec Symfony

Découvrez comment intégrer React dans votre application Symfony HYPER simplement

Découvrez comment intégrer React dans votre application Symfony HYPER simplement

Objectifs

Dans cet article, nous allons voir comment intégrer React dans une application Symfony. Nous allons voir comment créer un composant React, le rendre disponible dans notre application Symfony et l’utiliser dans une page Twig avec l’aide de Webpack Encore et Symfony UX React !

Installons un projet Symfony

  • Commençons par créer un projet Symfony 6
symfony new ReactSymfony --webapp
  • Puis installons les dépendances nécessaires
composer require symfony/webpack-encore-bundle
composer require symfony/ux-react
  • Téléchargeons ensuite les dépendances NPM
npm install --force
  • Installons Tailwind CSS
npm install -D tailwindcss postcss autoprefixer postcss-loader
npx tailwindcss init -p
  • Ajoutons PostCSS dans le fichier webpack.config.js
Encore
  // ...
  .enablePostCssLoader()
;
  • Modifions la configuration de Tailwind CSS dans le fichier tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./assets/**/*.js",
    "./templates/**/*.html.twig",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
  • Ajoutons les styles de Tailwind CSS dans le fichier assets/app.css
@tailwind base;
@tailwind components;
@tailwind utilities;

Créons un contrôleur ReactController

  • Créons un contrôleur ReactController avec la commande suivante
symfony console make:controller ReactController
  • Modifion notre fichier Twig react/index.html.twig
{% extends 'base.html.twig' %}

{% block title %}Hello ReactController!
{% endblock %}

{% block body %}
	<div class="bg-white">
		<div class="mx-auto max-w-7xl py-16 px-4 sm:py-24 sm:px-6 lg:px-8">
			<div class="text-center">
				<p class="mt-1 text-4xl font-bold tracking-tight text-gray-900 sm:text-5xl lg:text-6xl">Ceci est une démo de React dans une application Symfony</p>
				<p class="mx-auto mt-5 max-w-xl text-xl text-gray-500">Ceci est une démo de React dans une application Symfony</p>
            </div>
		</div>
	</div>
{% endblock %}

Créons et utilisons un composant React

  • Un peu de configuration avant de commencer, installez les dépendances suivantes
npm install @babel/preset-react@^7.0.0 --save-dev
  • Et activons React dans le fichier webpack.config.js
Encore
  // ...
  .enableReactPreset()
;

```json
{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react"
  ]
}
  • Ajoutons la gestion des composants React dans le fichier assets/app.js
import { registerReactControllerComponents } from '@symfony/ux-react';
registerReactControllerComponents(require.context('./react/controllers', true, /\.(j|t)sx?$/));
  • Créons un composant React (issue de la documentation officielle de Symfony) dans le fichier assets/react/controllers/MyComponent.jsx
import React from 'react';

export default function (props) {
    return <div>Hello {props.fullName}</div>;
}
  • Utilisons notre composant React dans notre code Twig:
{% block body %}
	<div class="bg-white">
		<div class="mx-auto max-w-7xl py-16 px-4 sm:py-24 sm:px-6 lg:px-8">
			<div class="text-center">
				<p class="mt-1 text-4xl font-bold tracking-tight text-gray-900 sm:text-5xl lg:text-6xl">Ceci est une démo de React dans une application Symfony</p>
				<p class="mx-auto mt-5 max-w-xl text-xl text-gray-500">Ceci est une démo de React dans une application Symfony</p>
                <div {{ react_component('MyComponent', { 'fullName': 'YoanDev' }) }}></div>
            </div>
		</div>
	</div>
{% endblock %}
  • Et voilà, notre composant React est maintenant disponible dans notre application Symfony !

Un composant React plus complexe

Pour la suite nous allon sutiliser la superbe librairie Headless UI qui permet de créer des composants React très facilement, bien adpatés à Tailwind CSS 💗


* Installons Headless UI

```bash
npm install @headlessui/react
  • Indiquons à Tailwind CSS de surveiller nos composants React
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./assets/**/*.js",
    "./templates/**/*.html.twig",
    "./assets/react/controllers/*.jsx",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
  • Créons un composant React plus complexe dans le fichier assets/react/controllers/Modal.jsx
import React from 'react';
import { Dialog, Transition } from "@headlessui/react";
import { Fragment, useState } from "react";

export default function MyModal() {
    let [isOpen, setIsOpen] = useState(true);

    function closeModal() {
        setIsOpen(false);
    }

    function openModal() {
        setIsOpen(true);
    }

    return (
        <>
            <div className="fixed inset-0 flex items-center justify-center">
                <button
                    type="button"
                    onClick={openModal}
                    className="rounded-md bg-black bg-opacity-20 px-4 py-2 text-sm font-medium text-white hover:bg-opacity-30 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75"
                >
                    Open dialog
                </button>
            </div>

            <Transition appear show={isOpen} as={Fragment}>
                <Dialog as="div" className="relative z-10" onClose={closeModal}>
                    <Transition.Child
                        as={Fragment}
                        enter="ease-out duration-300"
                        enterFrom="opacity-0"
                        enterTo="opacity-100"
                        leave="ease-in duration-200"
                        leaveFrom="opacity-100"
                        leaveTo="opacity-0"
                    >
                        <div className="fixed inset-0 bg-black bg-opacity-25" />
                    </Transition.Child>

                    <div className="fixed inset-0 overflow-y-auto">
                        <div className="flex min-h-full items-center justify-center p-4 text-center">
                            <Transition.Child
                                as={Fragment}
                                enter="ease-out duration-300"
                                enterFrom="opacity-0 scale-95"
                                enterTo="opacity-100 scale-100"
                                leave="ease-in duration-200"
                                leaveFrom="opacity-100 scale-100"
                                leaveTo="opacity-0 scale-95"
                            >
                                <Dialog.Panel className="w-full max-w-md transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all">
                                    <Dialog.Title
                                        as="h3"
                                        className="text-lg font-medium leading-6 text-gray-900"
                                    >
                                        Payment successful
                                    </Dialog.Title>
                                    <div className="mt-2">
                                        <p className="text-sm text-gray-500">
                                            Your payment has been successfully
                                            submitted. We’ve sent you an email
                                            with all of the details of your
                                            order.
                                        </p>
                                    </div>

                                    <div className="mt-4">
                                        <button
                                            type="button"
                                            className="inline-flex justify-center rounded-md border border-transparent bg-blue-100 px-4 py-2 text-sm font-medium text-blue-900 hover:bg-blue-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
                                            onClick={closeModal}
                                        >
                                            Got it, thanks!
                                        </button>
                                    </div>
                                </Dialog.Panel>
                            </Transition.Child>
                        </div>
                    </div>
                </Dialog>
            </Transition>
        </>
    );
}
  • Et utilisons le dans notre code Twig:
{% block body %}
    <div class="bg-white">
        <div class="mx-auto max-w-7xl py-16 px-4 sm:py-24 sm:px-6 lg:px-8">
            <div class="text-center">
                <p class="mt-1 text-4xl font-bold tracking-tight text-gray-900 sm:text-5xl lg:text-6xl">Ceci est une démo de React dans une application Symfony</p>
                <p class="mx-auto mt-5 max-w-xl text-xl text-gray-500">Ceci est une démo de React dans une application Symfony</p>
                <div {{ react_component('MyComponent', { 'fullName': 'YoanDev' }) }}></div>
                <div {{ react_component('Modal') }}></div>
            </div>
        </div>
    </div>
{% endblock %}
  • Modifions notre fichier assets/react/controllers/Modal.jsx pour pouvoir passer des paramètres à notre composant React
export default function MyModal(props) {
    // ...
}
  • Et utilisons une props pour changer le libelé de nos boutons
// ...
<div className="fixed inset-0 flex items-center justify-center">
    <button
        type="button"
        onClick={openModal}
        className="rounded-md bg-black bg-opacity-20 px-4 py-2 text-sm font-medium text-white hover:bg-opacity-30 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75"
    >
        {props.button}
    </button>
</div>
// ...

<div className="mt-4">
    <button
        type="button"
        className="inline-flex justify-center rounded-md border border-transparent bg-blue-100 px-4 py-2 text-sm font-medium text-blue-900 hover:bg-blue-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
        onClick={closeModal}
    >
        {props.button}
    </button>
</div>
// ...
  • Et enfin, depuis notre fichier Twig on peut passer des paramètres à notre composant React
<div {{ react_component('Modal', { 'button': 'YoanDev Button'}) }}></div>

Conclusion

Nous avons vu comment utiliser React dans une application Symfony. Nous avons vu comment créer un composant React, comment l’importer dans notre application Symfony et comment l’utiliser dans un fichier Twig. Nous avons aussi vu comment passer des paramètres à notre composant React depuis notre fichier Twig.

Nous en avons profité pour voir comment utiliser TailwindCSS et HeadlessUI pour notre plus grand plaisir.

Back to Blog