react-sortablejs icon indicating copy to clipboard operation
react-sortablejs copied to clipboard

Cannot set property 'chosen' of undefined

Open NARUTOne opened this issue 5 years ago • 12 comments

if lists length is 2. Drag up and down several times image

NARUTOne avatar Jun 01 '20 10:06 NARUTOne

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

DZakh avatar Jul 08 '20 16:07 DZakh

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.

DZakh avatar Jul 08 '20 17:07 DZakh

I added onChoose callback and took a look at the event object. image 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.

DZakh avatar Jul 08 '20 17:07 DZakh

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

DZakh avatar Jul 08 '20 17:07 DZakh

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: image

I'm gonna create a PR with a check for immutable data. Please accept it, the bug is very critical for me.

DZakh avatar Jul 08 '20 17:07 DZakh

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 avatar Jul 10 '20 07:07 prtk0317

@prtk0317, well, immer weights 1kb more than this library. Moreover, there is absolutely no need in this useless abstraction.

DZakh avatar Jul 10 '20 07:07 DZakh

How about to close the issue?

DZakh avatar Jul 12 '20 14:07 DZakh

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 avatar Aug 21 '20 23:08 sanchito59

@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)

DZakh avatar Aug 22 '20 11:08 DZakh

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.

ProfessorX737 avatar Aug 27 '20 14:08 ProfessorX737

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

aishuaikang avatar Feb 02 '24 06:02 aishuaikang