带有 React.js 错误的 jQuery UI 可排序
Posted
技术标签:
【中文标题】带有 React.js 错误的 jQuery UI 可排序【英文标题】:jQuery UI Sortable with React.js buggy 【发布时间】:2015-06-25 20:03:21 【问题描述】:我在 React 中有一个由 jQuery UI 提供支持的可排序列表。当我在列表中拖放一个项目时,我想更新数组,以便将列表的新顺序存储在那里。然后使用更新的数组重新渲染页面。即this.setState(data: _todoList);
目前,当您拖放一个项目时,jQuery UI DnD 可以工作,但该项目在 UI 中的位置不会改变,即使页面使用更新后的数组重新呈现也是如此。即在 UI 中,项目恢复到它以前在列表中的位置,即使定义其位置的数组已成功更新。
如果您拖放项目两次,则它会移动到正确的位置。
// 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>
)
);
【问题讨论】:
这是一个可能有用的例子:gist.github.com/petehunt/7882164 感谢@MikeDriver 的建议,但这一行让我觉得“要注意的关键是我们的 render() 方法完全什么都不做”。我正在尝试利用渲染方法来保持 React/Flux 架构。 我觉得如果你偏离了反应架构,足以使用 jquery 插件而不是等效的原生功能来反应 - 那么必须做出妥协。我并不是说你不应该在 react 中使用 jquery 插件 - 显然在某些情况下这是唯一实用的解决方案,但是试图让事情保持“反应性”有点在马用螺栓 IMO 之后关闭谷仓门. 【参考方案1】:由于 React 使用虚拟 DOM,因此您必须使用函数 React.findDOMNode() 来访问实际的 DOM 元素。
我会在组件的 componentDidMount 方法中调用 jQuery UI 函数,因为您的元素必须已经渲染才能访问。
// 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 the browser(你想知道的都在这里)
希望有意义并解决您的问题
【讨论】:
【参考方案2】:jQuery UI Sortable 不能与 React 一起工作的原因是因为它直接改变了 DOM,这在 React 中是一个很大的no no。
要使其工作,您必须修改 jQuery UI Sortable 以保留 DnD 功能,但是当您删除元素时,它不会修改 DOM。相反,它可以触发一个事件,触发 React 渲染与元素的新位置。
【讨论】:
【参考方案3】:诀窍是在 Sortable 的 stop
事件中调用 sortable('cancel')
,然后让 React 更新 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)))))
)
【讨论】:
谢谢!这是迄今为止我发现的最简单的解决方法 是的!cancel
是唯一有效的——100% 优于实现“可排序”ReactJS 组件以上是关于带有 React.js 错误的 jQuery UI 可排序的主要内容,如果未能解决你的问题,请参考以下文章
将带有 jquery 的 html 模板转换为 React js
我想在useEffect react Js中使用带有foreach的axios,但它给了我(无法读取属性Symbol(Symbol.iterator)错误?
如何在 Material UI (React JS) 中根据需要制作“选择”组件