JQuery Sortable UI with React.js Buggy

I have a sorted list in React that works from jQuery UI. When I drag an item in a list, I want to update the array so that the new list order is saved there. Then redeploy the page with the updated array. those. this.setState({data: _todoList});

Currently, when dragging and dropping a jQuery element, the DnD UI works, but the position of the element in the user interface does not change, even if the page re-displays with the updated array. that is, in the user interface, the element returns to the place where it was included in the list, although the array that determines its location was successfully updated.

If you double-drag an item, then move to the correct position.

  // Enable jQuery UI Sortable functionality $(function() { $('.bank-entries').sortable({ axis: "y", containment: "parent", tolerance: "pointer", revert: 150, start: function (event, ui) { ui.item.indexAtStart = ui.item.index(); }, stop: function (event, ui) { var data = { indexStart: ui.item.indexAtStart, indexStop: ui.item.index(), accountType: "bank" }; AppActions.sortIndexes(data); }, }); }); // This is the array that holds the positions of the list items var _todoItems = {bank: []}; var AppStore = assign({}, EventEmitter.prototype, { getTodoItems: function() { return _todoItems; }, emitChange: function(change) { this.emit(change); }, addChangeListener: function(callback) { this.on(AppConstants.CHANGE_EVENT, callback); }, sortTodo: function(todo) { // Dynamically choose which Account to target targetClass = '.' + todo.accountType + '-entries'; // Define the account type var accountType = todo.accountType; // Loop through the list in the UI and update the arrayIndexes // of items that have been dragged and dropped to a new location // newIndex is 0-based, but arrayIndex isn't, hence the crazy math $(targetClass).children('form').each(function(newIndex) { var arrayIndex = Number($(this).attr('data-array-index')); if (newIndex + 1 !== arrayIndex) { // Update the arrayIndex of the element _todoItems[accountType][arrayIndex-1].accountData.arrayIndex = newIndex + 1; } }); // Sort the array so that updated array items move to their correct positions _todoItems[accountType].sort(function(a, b){ if (a.accountData.arrayIndex > b.accountData.arrayIndex) { return 1; } if (a.accountData.arrayIndex < b.accountData.arrayIndex) { return -1; } // a must be equal to b return 0; }); // Fire an event that re-renders the UI with the new array AppStore.emitChange(AppConstants.CHANGE_EVENT); }, } function getAccounts() { return { data: AppStore.getTodoItems() } } var Account = React.createClass({ getInitialState: function(){ return getAccounts(); }, componentWillMount: function(){ AppStore.addChangeListener(this._onChange); // Fires action that triggers the initial load AppActions.loadComponentData(); }, _onChange: function() { console.log('change event fired'); this.setState(getAccounts()); }, render: function(){ return ( <div className="component-wrapper"> <Bank data={this.state.data} /> </div> ) } }); 
+5
source share
3 answers

The reason jQuery UI Sortable doesn't work with React is because it directly mutates the DOM, which is not big in React.

To make it work, you will have to modify the JQuery UI Sortable to preserve DnD functionality, but when you delete an item, it does not change the DOM . Instead, it can fire an event that fires a React render with a new element position.

+6
source

The trick is to call sortable('cancel') on the stop event of the Sort file, then let React update the DOM.

 componentDidMount() { this.domItems = jQuery(React.findDOMNode(this.refs["items"])) this.domItems.sortable({ stop: (event, ui) => { // get the array of new index (http://api.jqueryui.com/sortable/#method-toArray) const reorderedIndexes = this.domItems.sortable('toArray', {attribute: 'data-sortable'}) // cancel the sort so the DOM is untouched this.domItems.sortable('cancel') // Update the store and let React update (here, using Flux) Actions.updateItems(Immutable.List(reorderedIndexes.map( idx => this.state.items.get(Number(idx))))) } }) } 
+8
source

Since React uses the virtual DOM, you must use the React.findDOMNode () function to access the actual DOM element.

I would call the jQuery UI function inside the componentDidMount method of your component, because your element must already be displayed for access.

 // You have to add a ref attribute to the element with the '.bank-entries' class $( React.findDOMNode( this.refs.bank_entries_ref ) ).sortable( /.../ ); 

Documentation - Working with a browser (everything you need to know here)

Hope this makes sense and solves your problem.

+2
source

All Articles