web-dev-qa-db-fra.com

Comment utiliser l'interface utilisateur de jQuery avec React JS

Comment utiliser l'interface utilisateur de jQuery avec React? J'ai vu quelques exemples de Google, mais tous semblent être obsolètes.

42
Tahnik Mustasin

React ne fonctionne pas bien avec les bibliothèques qui effectuent des mutations directes dans le DOM. Si quelque chose d'autre mute le DOM où React tente de restituer, des erreurs se produiront. Si vous aviez pour que cela fonctionne, votre meilleur compromis est d’avoir différentes parties de votre page gérées par différentes choses, par exemple une div qui héberge votre (vos) composant (s) jquery, puis une autre div qui contient votre ou vos composants React. La communication entre ces composants disparates (jQuery et Rea) sera difficile, mais honnêtement, il vaut probablement mieux choisir l'un ou l'autre.

12
John

Bien que techniquement irréprochable, la réponse de Kayolan a un défaut fatal, IMHO: en passant la responsabilité des futures mises à jour de l'interface utilisateur de React à jQuery, il a plutôt nié le fait que React soit présent! React contrôle le rendu initial de la liste triable, mais après cela, les données d'état de React deviendront obsolètes dès que l'utilisateur aura effectué les premières opérations de glissement/tri jQueryUI. Et tout l'intérêt de React est de représenter vos données d'état au niveau de la vue.

J'ai donc adopté l'approche inverse en abordant ce problème: j'ai essayé de faire en sorte que React soit en contrôle le plus possible. Je ne laisse pas le contrôle jQueryUI Sortable changer le DOM du tout.

Comment est-ce possible? La méthode sortable () de jQuery-ui a un appel cancel qui redéfinit l'interface utilisateur à son état actuel avant que vous ne commenciez à faire glisser des éléments. L'astuce consiste à lire l'état du contrôle triable avant que vous lanciez cet appel cancel. De cette façon, nous pouvons déterminer ce que sont les intentions de l'utilisateur, avant l'appel cancel, pour que le DOM redevienne comme avant. Une fois que nous avons ces intentions, nous pouvons les renvoyer à React et manipuler les données d'état pour qu'elles soient dans le nouvel ordre souhaité par l'utilisateur. Enfin, appelez setState () sur ces données pour que React rende le nouvel ordre.

Voici comment je fais ça:

  1. Associez la méthode jquery-ui.sortable () à une liste d'éléments de ligne (générée par React bien sûr!)
  2. Laissez l'utilisateur glisser-déposer ces éléments de ligne autour du DOM.
  3. Lorsque l'utilisateur commence à faire glisser, nous lisons l'index de l'élément de campagne que l'utilisateur a fait glisser depuis.
  4. Lorsque l'utilisateur supprime l'élément de campagne, nous: .____.
    1. Lisez à partir de jQuery-ui.sortable () la nouvelle position d'index de l'élément de ligne, c'est-à-dire où, dans la liste, l'utilisateur a abandonné.
    2. Passez un appel cancel à jQuery-ui.sortable () afin que la liste revienne à sa position d'origine et que le DOM ne soit pas modifié.
    3. Transmettez les anciens et les nouveaux index de l'élément de campagne déplacé en tant que paramètres à une fonction JavaScript dans un module React.
    4. Demandez à cette fonction de réorganiser les données d'état d'arrière-plan de la liste pour qu'elles soient dans le nouvel ordre dans lequel l'utilisateur les a fait glisser.
    5. Effectuez un appel à React setState().

La liste dans l'interface utilisateur va maintenant refléter le nouvel ordre de nos données d'état; c'est la fonctionnalité standard de React.

Nous pouvons donc utiliser la fonctionnalité glisser-déposer de jQueryUI Sortable, mais sans modifier le DOM. React est heureux, car il contrôle le DOM (où il devrait être).

Exemple de référentiel Github à https://github.com/brownieboy/react-dragdrop-test-simple . Cela inclut un lien vers une démonstration en direct.

7
ChillyPenguin

En ce qui concerne réponse longue de Kaloyan Kosev } _, je dois créer un composant pour chaque fonction jQueryUi que je souhaite utiliser? Non merci! Pourquoi ne pas simplement mettre à jour votre state lorsque vous modifiez le DOM? Followig fonctionne pour moi:

export default class Editor extends React.Component {

    // ... constructor etc.

    componentDidMount() {
        this.initializeSortable();
    }

    initializeSortable() {
        const that = this;
        $('ul.sortable').sortable({
            stop: function (event, ui) {
                const usedListItem = ui.item;
                const list = usedListItem.parent().children();
                const orderedIds = [];
                $.each(list, function () {
                    orderedIds.Push($(this).attr('id'));
                })
                that.orderSortableListsInState(orderedIds);
            }
        });
    }

    orderSortableListsInState(orderedIds) {

        // ... here you can sort the state of any list in your state tree

        const orderedDetachedAttributes = this.orderListByIds(orderedIds, this.state.detachedAttributes);
        if (orderedDetachedAttributes.length) {
            this.state.detachedAttributes = orderedDetachedAttributes;
        }
        this.setState(this.state);
    }

    orderListByIds(ids, list) {
        let orderedList = [];
        for (let i = 0; i < ids.length; i++) {
            let item = this.getItemById(ids[i], list);
            if (typeof item === 'undefined') {
                continue;
            }
            orderedList.Push(item);
        }
        return orderedList;
    }

    getItemById(id, items) {
        return items.find(item => (item.id === id));
    }

    // ... render etc.

}

L'élément de liste a simplement besoin d'un attribut supplémentaire pour permettre à jQuery de sélectionner l'élément.

import React from 'react';

export default class Attributes extends React.Component {
    render() {
        const attributes = this.props.attributes.map((attribute, i) => {
           return (<li key={attribute.id} id={attribute.id}>{attribute.name}</li>);
        });

        return (
            <ul className="sortable">
                {attributes}
            </ul>
        );
    }
}

Pour les identifiants, j'utilise UUID , donc je n'ai pas de conflits lors de leur correspondance dans orderSortableListsInState().

0
Fabian Picone

Je ne pouvais pas faire fonctionner le paquet jquery-ui npm. Ce qui a fonctionné pour moi est d’utiliser jquery-ui-bundle:

import $ from 'jquery';
import 'jquery-ui-bundle';
import 'jquery-ui-bundle/jquery-ui.min.css';
0
SamuraiCharlie