¿Cómo usar jquery ui con React JS?

He visto un par de ejemplos en Google, pero todos parecen estar desactualizados. ¿Alguna idea de cómo puedo usar Jquery UI con reactjsr?

Si realmente necesita hacer eso, aquí hay un enfoque que estoy usando.

El plan: crea un componente para administrar el complemento jQuery . Este componente proporcionará una vista centrada en React del componente jQuery. Por otra parte, será:

  • Use los métodos del ciclo de vida Reaccionar para inicializar y eliminar el plugin jQuery;
  • Utilice React props como opciones de configuración del complemento y conéctese a los eventos de métodos del complemento;
  • Destruye el complemento cuando el componente se desmonta.

Analicemos un ejemplo práctico de cómo hacerlo con el complemento jQuery UI Sortable .


TLDR: la versión final

Si solo quieres obtener la versión final del ejemplo ordenado jQuery UI Sortable:

  • aquí hay un GIST que hice con comentarios anotados completos;
  • y aquí hay una DEMO jsfiddle , comentarios anotados completos también;

… además, a continuación se abrevia el fragmento de código de comentarios más largos :

 class Sortable extends React.Component { componentDidMount() { this.$node = $(this.refs.sortable); this.$node.sortable({ opacity: this.props.opacity, change: (event, ui) => this.props.onChange(event, ui) }); } shouldComponentUpdate() { return false; } componentWillReceiveProps(nextProps) { if (nextProps.enable !== this.props.enable) this.$node.sortable(nextProps.enable ? 'enable' : 'disable'); } renderItems() { return this.props.data.map( (item, i) => 
  • { item }
  • ); } render() { return (
      { this.renderItems() }
    ); } componentWillUnmount() { this.$node.sortable('destroy'); } };

    Opcionalmente, puede establecer apoyos por defecto (en el caso de que no se pasen ninguno) y los tipos de utilería:

     Sortable.defaultProps = { opacity: 1, enable: true }; Sortable.propTypes = { opacity: React.PropTypes.number, enable: React.PropTypes.bool, onChange: React.PropTypes.func.isRequired }; 

    … y así es cómo usar el :

     class MyComponent extends React.Component { constructor(props) { super(props); // Use this flag to disable/enable the  this.state = { isEnabled: true }; this.toggleEnableability = this.toggleEnableability.bind(this); } toggleEnableability() { this.setState({ isEnabled: ! this.state.isEnabled }); } handleOnChange(event, ui) { console.log('DOM changed!', event, ui); } render() { const list = ['ReactJS', 'JSX', 'JavaScript', 'jQuery', 'jQuery UI']; return ( 
    ); } } ReactDOM.render(, document.getElementById('app'));

    La Explicación Completa

    Para aquellos de ustedes que quieren entender por qué y cómo . Aquí hay una guía paso a paso:

    Paso 1: crea un componente.

    Nuestro componente aceptará una matriz (lista) de elementos (cadenas) como soporte de data .

     class Sortable extends React.Component { componentDidMount() { // Every React component has a function that exposes the // underlying DOM node that it is wrapping. We can use that // DOM node, pass it to jQuery and initialize the plugin. // You'll find that many jQuery plugins follow this same pattern // and you'll be able to pass the component DOM node to jQuery // and call the plugin function. // Get the DOM node and store the jQuery element reference this.$node = $(this.refs.sortable); // Initialize the jQuery UI functionality you need // in this case, the Sortable: https://jqueryui.com/sortable/ this.$node.sortable(); } // jQuery UI sortable expects a 
      list with
    • s. renderItems() { return this.props.data.map( (item, i) =>
    • { item }
    • ); } render() { return (
      { this.renderItems() }
    ); } };

    Paso 2: pase las opciones de configuración a través de accesorios

    Digamos que queremos configurar la opacidad del helper mientras ordenamos . Utilizaremos la opción de opacity en la configuración del complemento, que toma valores de 0.01 a 1 .

     class Sortable extends React.Component { // ... omitted for brevity componentDidMount() { this.$node = $(this.refs.sortable); this.$node.sortable({ // Get the incoming `opacity` prop and use it in the plugin configuration opacity: this.props.opacity, }); } // ... omitted for brevity }; // Optional: set the default props, in case none are passed Sortable.defaultProps = { opacity: 1 }; 

    Y así es cómo podemos usar el componente en nuestro código ahora:

      

    De la misma manera, podemos mapear cualquiera de las opciones ordenables de la interfaz de usuario de Jimmy .

    Paso 3: Funciones de conexión en eventos de complementos.

    Lo más probable es que necesite conectar algunos de los métodos de complemento, para realizar alguna lógica de Reaccionar, por ejemplo, manipular el estado del día.

    He aquí cómo hacerlo:

     class Sortable extends React.Component { // ... omitted for brevity componentDidMount() { this.$node = $(this.refs.sortable); this.$node.sortable({ opacity: this.props.opacity, // Get the incoming onChange function // and invoke it on the Sortable `change` event change: (event, ui) => this.props.onChange(event, ui) }); } // ... omitted for brevity }; // Optional: set the prop types Sortable.propTypes = { onChange: React.PropTypes.func.isRequired }; 

    Y aquí está cómo usarlo:

      console.log('DOM changed!', event, ui) } /> 

    Paso 4: Pase el control de actualizaciones futuras a jQuery

    Justo después de que ReactJS agregue el elemento en el DOM real, necesitamos pasar el control futuro a jQuery. De lo contrario, ReactJS nunca volverá a renderizar nuestro componente, pero no queremos eso. Queremos que jQuery sea responsable de todas las actualizaciones.

    React lifecycle methods viene al rescate!

    Use shouldComponentUpdate () para avisar a React si la salida de un componente no se ve afectada por el cambio actual en el estado o los accesorios. El comportamiento predeterminado es volver a procesar en cada cambio de estado, y en la gran mayoría, ¡pero no queremos este comportamiento!

    shouldComponentUpdate() se invoca antes de la representación cuando se reciben nuevos apoyos o estado. Si shouldComponentUpdate() devuelve false , entonces no se invocarán componentWillUpdate() , render() y componentDidUpdate() .

    Luego, usamos componentWillReceiveProps() , comparamos this.props con nextProps y llamamos a las actualizaciones ordenables de jQuery UI solo cuando es necesario. Para este ejemplo, implementaremos la opción activar / desactivar de jQuery UI ordenable.

     class Sortable extends React.Component { // Force a single-render of the component, // by returning false from shouldComponentUpdate ReactJS lifecycle hook. // Right after ReactJS adds the element in the actual DOM, // we need to pass the future control to jQuery. // This way, ReactJS will never re-render our component, // and jQuery will be responsible for all updates. shouldComponentUpdate() { return false; } componentWillReceiveProps(nextProps) { // Each time when component receives new props, // we should trigger refresh or perform anything else we need. // For this example, we'll update only the enable/disable option, // as soon as we receive a different value for this.props.enable if (nextProps.enable !== this.props.enable) { this.$node.sortable(nextProps.enable ? 'enable' : 'disable'); } } // ... omitted for brevity }; // Optional: set the default props, in case none are passed Sortable.defaultProps = { enable: true }; // Optional: set the prop types Sortable.propTypes = { enable: React.PropTypes.bool }; 

    Paso 5: Limpia el desorden.

    Muchos complementos jQuery proporcionan un mecanismo para limpiar después de ellos mismos cuando ya no son necesarios. jQuery UI Sortable proporciona un evento que podemos activar para decirle al complemento que desvincula los eventos DOM y los destruya. Los métodos del ciclo de vida de Reaay vuelven a rescatar y proporcionan un mecanismo para enganchar cuando se desmonta el componente.

     class Sortable extends React.Component { // ... omitted for brevity componentWillUnmount() { // Clean up the mess when the component unmounts this.$node.sortable('destroy'); } // ... omitted for brevity }; 

    Conclusión

    Envolver complementos jQuery con React no siempre es la mejor opción. Sin embargo, es bueno saber que es una opción y cómo puede implementar una solución. Es una opción viable si está migrando una aplicación jQuery heredada a React o tal vez simplemente no puede encontrar un complemento React que se adapte a sus necesidades en su caso.

    En el caso de que una biblioteca modifique el DOM, tratamos de mantener a React fuera de su camino . React funciona mejor cuando tiene control total del DOM. En estos casos, los componentes de React son más envoltorios para las bibliotecas de terceros. Principalmente mediante el uso de componentDidMount / componentWillUnmount para inicializar / destruir la biblioteca de terceros. Y apoyos como una forma de darle al padre una forma de personalizar el comportamiento de la biblioteca de terceros que el niño envuelve y conectar en eventos de complementos.

    ¡Puedes utilizar este enfoque para integrar casi cualquier plugin jQuery !

    Reaccionar no funciona bien con bibliotecas que dirigen mutaciones DOM. Si algo más muta el DOM donde React intenta renderizar, arrojará errores. Si tiene que hacer esto, su mejor compromiso es tener diferentes partes de su página administradas por diferentes elementos, por ejemplo, un div que aloje su (s) componente (s) jquery, y luego otro div que contenga su componente React ( s). Sin embargo, la comunicación entre estos componentes dispares (jquery y reactjsr) será difícil y, sinceramente, es mejor simplemente elegir uno u otro.

    Aunque técnicamente es impecable, la respuesta de Kayolan tiene un defecto fatal, en mi humilde opinión: al pasar la responsabilidad de futuras actualizaciones de la interfaz de usuario de React a jQuery, ¡más bien se niega a que React esté allí en primer lugar! React controla la representación inicial de la lista ordenable, pero después de eso, los datos de estado de React quedarán obsoletos tan pronto como el usuario realice las primeras operaciones de arrastrar / ordenar jQueryUI. Y el objective de React es representar los datos de su estado en el nivel de vista.

    Entonces, tomé el enfoque inverso cuando me acerqué a este problema: intenté asegurarme de que React tuviera el control tanto como fuera posible. No dejo que el control ordenable jQueryUI cambie el DOM en absoluto .

    ¿Como es eso posible? Bueno, el método sortable () de jQuery-ui tiene una llamada de cancel que restablece la UI a cómo era antes de que comenzaras a arrastrar y soltar cosas. El truco es leer el estado del control clasificable antes de emitir esa llamada cancel . De esta forma, podemos detectar cuáles eran las intenciones del usuario, antes de que la llamada cancel establezca el DOM como estaba. Una vez que tenemos esas intenciones, podemos devolverlas a React y manipular los datos de estado para que estén en el nuevo orden que el usuario quería. Finalmente, llame a setState () sobre esos datos para que React represente la nueva orden.

    Así es como hago eso:

    1. Adjunte el método jquery-ui.sortable () a una lista de artículos de línea (¡generados por Reaccionar, por supuesto!)
    2. Permita que el usuario arrastre y suelte esas líneas de pedido alrededor del DOM.
    3. Cuando el usuario comienza a arrastrar, leemos el índice de la línea de pedido desde la cual el usuario está arrastrando.
    4. Cuando el usuario descarta la línea de pedido, nosotros:
      1. Lea desde jQuery-ui.sortable () la nueva posición de índice para la línea de pedido, es decir, en qué parte de la lista lo dejó el usuario.
      2. Pase una llamada de cancel a jQuery-ui.sortable () para que la lista vuelva a su posición original y el DOM no se modifique.
      3. Pase los índices antiguos y nuevos de la línea de pedido arrastrada como parámetros a una función de JavaScript en un módulo Reaccionar.
      4. Haga que esa función vuelva a ordenar los datos de estado de la lista de la lista para que estén en el nuevo orden que el usuario arrastró y soltó.
      5. Haga una setState() React setState() .

    La lista en la interfaz de usuario ahora reflejará el nuevo orden de los datos de nuestro estado; esto es la funcionalidad Reaccionar estándar.

    Entonces, podemos usar la funcionalidad de arrastrar y soltar de jQueryUI Sortable, pero sin cambiar el DOM en absoluto. Reaccionar es feliz, porque tiene el control del DOM (donde debería estar).

    Ejemplo de repository de Github en https://github.com/brownieboy/react-dragdrop-test-simple . Esto incluye un enlace a una demostración en vivo.

    Con respecto a la respuesta larga de Kaloyan Kosev , ¿debo crear un componente para cada característica jQueryUi que quiero usar? ¡No, gracias! ¿Por qué no simplemente actualizar su estado cuando cambia el DOM ? Followig trabaja para mí:

     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. } 

    El elemento de lista solo necesita un atributo adicional para que jQuery seleccione el elemento.

     import React from 'react'; export default class Attributes extends React.Component { render() { const attributes = this.props.attributes.map((attribute, i) => { return (
  • {attribute.name}
  • ); }); return (
      {attributes}
    ); } }

    Para los identificadores utilizo los UUID , por lo que no orderSortableListsInState() conflictos cuando los orderSortableListsInState() en orderSortableListsInState() .