react-sortablejs
react-sortablejs copied to clipboard
Cannot set property 'chosen' of undefined
if lists length is 2. Drag up and down several times

I have a different error. It happens after I rerender one element of the list

Ah, no, it's the same.
Here's my component
import React, { useState, useEffect } from 'react';
import { ReactSortable } from 'react-sortablejs';
import map from 'lodash/map';
import Field from './Field';
import style from './style.module.css';
const FIELD_DRAG_HANDLE_CLASS = 'FIELD_DRAG_HANDLE_CLASS';
const FieldsList = ({
fields: initialFields,
onDelete,
onEdit,
updateFields,
blockDragIgnoreCn,
}) => {
const [sortingFields, setSortingFields] = useState(initialFields);
useEffect(() => {
setSortingFields(initialFields);
}, [initialFields]);
return (
<ReactSortable
list={sortingFields}
setList={(newState) => setSortingFields(newState)}
animation={100}
forceFallback
handle={`.${FIELD_DRAG_HANDLE_CLASS}`}
fallbackClass={style.field_drag_fallback}
onEnd={() => {
updateFields(sortingFields);
}}
>
{map(sortingFields, ({ title, id, fields }) => (
<Field
key={id}
title={title}
id={id}
fields={fields}
blockDragIgnoreCn={blockDragIgnoreCn}
dragHandleClass={FIELD_DRAG_HANDLE_CLASS}
onDelete={onDelete}
onEdit={onEdit}
/>
))}
</ReactSortable>
);
};
export default FieldsList;
When I try to drag a changed item, it crashes. A changed item has the same id, key and idx. So it shouldn't be a problem.
I added onChoose callback and took a look at the event object.
It doesn't have a problem here. The problem is either inside of your component or it uses some weird version of a list variable. I'm gonna try to add some debuggers in your code, maybe I'll find the source of the problem.
I don't know what's the problem, but if we ignore the problem the sorting at least works.
Also, I've checked, the object inside of the list isn't frozen nor with preventExtensions.

Ah, no, I'm wrong. It's both Frozen and sealed.
For this line
console.log(newList, newList[evt.oldIndex], evt, Object.isFrozen(newList[evt.oldIndex]), Object.isSealed(newList[evt.oldIndex]), Object.isExtensible(newList[evt.oldIndex]));
It returned the following thing:

I'm gonna create a PR with a check for immutable data. Please accept it, the bug is very critical for me.
Use immer immutable state
import { produce } from 'immer';
ReactSortable.prototype.onChoose = function (evt) {
var _a = this.props, list = _a.list, setList = _a.setList;
var newList = produce(list, function (draftState) {
draftState[evt.oldIndex].chosen = true;
});
setList(newList, this.sortable, store);
};
ReactSortable.prototype.onUnchoose = function (evt) {
var _a = this.props, list = _a.list, setList = _a.setList;
var newList = produce(list, function (draftState) {
draftState[evt.oldIndex].chosen = false;
});
setList(newList, this.sortable, store);
};
@prtk0317, well, immer weights 1kb more than this library. Moreover, there is absolutely no need in this useless abstraction.
How about to close the issue?
hey @DZakh, not sure if you've solved this in your particular use case, but I had a very similar issue with with my code. Key differences are that I passed my equivalent of setList={(newState) => setSortingFields(newState)} into ReactSortable as setList={setSortingFields}, and I also switched my use of:
useEffect(() => {
setSortingFields(initialFields);
}, [initialFields]);
To detect changes, it is now memoizing the value changes using:
useMemo(() => {
setSortingFields(initialFields);
}, [initialFields]);
@sanchito59 My problem was because of immer, that made objects frozen. UseMemo shouldn't affect values in any way. If it does, you can try the last commit from the master branch, maybe my solution will help you. (it's still not published on npm)
What is the use of choose and unchoose? I have never found a case where setList is called with choose = true
As a quick workaround I am doing:
import { ReactSortable } from "react-sortablejs";
ReactSortable.prototype.onChoose = () => {};
ReactSortable.prototype.onUnchoose = () => {};
To overwrite the code. It doesn't seem to impact the functionality at all because of the above reason.
What is the use of choose and unchoose? I have never found a case where setList is called with choose = true
As a quick workaround I am doing:
import { ReactSortable } from "react-sortablejs"; ReactSortable.prototype.onChoose = () => {}; ReactSortable.prototype.onUnchoose = () => {};To overwrite the code. It doesn't seem to impact the functionality at all because of the above reason.
nice