react-sortable-hoc icon indicating copy to clipboard operation
react-sortable-hoc copied to clipboard

Cannot read property 'removeChild' of null

Open baiyuze opened this issue 5 years ago • 10 comments

I used onMouseDown to delete items data, and I reported this error, unable to locate what the problem was.

      <div
        className='icon-close'
        onMouseDown={this.onDelete.bind(this, value)}>
        <Icon
          type="close-circle"
          className='icon-close' />
      </div>
  onDelete(value: string) {
    console.log(value, 'value')
    let { items } = this.state;
    items = items!.filter((item: string) => item !== value);
    this.setState({ items }, () => {
      this.props.onDelete && this.props.onDelete(items);
    })
  }

image

Deleting will result in an error and a request will be sent. I don't know where the request originated and whether it can be blocked

I need help Thank you

baiyuze avatar May 28 '19 13:05 baiyuze

I believe I may have run into a related issue after updating to the latest version of react-sortable-hoc.

I was incorrectly calling React setState in the SortableContainer's onSortStart callback. After reading the documentation it doesn't appear that calling setState is supported in this context (I may not be correct about this).

I tried moving the setState call to updateBeforeSortStart instead, but started encountering some bizarre looking graphical bugs (the draggable item would appear like 600px away from it's correct position with ~50% opacity).

For my use case I was able to avoid calling setState entirely, settling for a NOP instead of a new rendering. Not ideal, but it got things working ok.

I'm using the latest versions of react-sortable-hoc, invariant, react, and react-dom.

rectangletangle avatar Jun 06 '19 00:06 rectangletangle

I have the exact same problem. I'm using the library with Redux and I'm getting the error even when not setting any state.

This is what my SortableList looks like (snippet of my component):

private getSortableList(jobs: Immutable.List<IJob>) {
    const SortableItem = SortableElement(({ value, disabled }: { value: IJob; disabled: boolean }) => (
        <Job job={value} key={value.get('jobId')} sortable={!disabled} />
    ));

    const SortableList = SortableContainer(({ items }: { items: Immutable.List<IJob> }) => (
        <div className='sortable-queue'>
            {items.map((job, idx) => (
                <SortableItem key={idx} index={idx} value={job} disabled={!this.isJobSortable(job)} />
            ))}
        </div>
    ));

    return (
        <SortableList
            items={jobs}
            useDragHandle
            key='sortableList'
            onSortEnd={this.handleQueueOrderChange}
        />
    );
}

private isJobSortable(job: IJob) {
    const status = job.get('status');
    return job.get('enqueued') && (status === 'idle' || status === 'error' || status === 'finished');
}

private handleQueueOrderChange({ newIndex, oldIndex }) {
    console.log(newIndex, oldIndex);
}

XeniaSiskaki avatar Jul 03 '19 09:07 XeniaSiskaki

I just had these same issues. It was caused by my SortableContainer and SortableElement being assigned inside of the render function. Meaning each time I set the state it would re-render and create a new instance of SortableContainer and SortableElement. That would divorce the old SortableElement from the DOM and cause the issues.

So the solution for me was to assign SortableContainer and SortableElement to variables outside of render() and reference those on render. Also, @rectangletangle is correct, updateBeforeSortStart should be used to set state rather that onSortStart.

cpwinn avatar Sep 17 '19 17:09 cpwinn

@cpwinn could you share a code snippet of your solution? I'm not sure how else to assign the SortableContainer and SortableElement if they depend on props.

XeniaSiskaki avatar Sep 18 '19 06:09 XeniaSiskaki

Good question @XeniaSiskaki. I passed my props and state from the top component down to SortableContainer and SortableElement as props like you already do with jobs.

Here is a modified version of your snippet that illustrates that. Hopefully that helps.

private getSortableList(jobs: Immutable.List<IJob>) {
    return (
        <SortableList
            items={jobs}
            useDragHandle
            key='sortableList'
            onSortEnd={handleQueueOrderChange}
            propA={props.propA}
            propB={props.propB}
        />
    );
}

const SortableList = SortableContainer(({ items, propA, propB }: { items: Immutable.List<IJob>; propA: any; propB: any }) => (
    <div className='sortable-queue'>
        {items.map((job, idx) => (
            <SortableItem key={idx} index={idx} value={job} disabled={!isJobSortable(job)} propB={propB} />
            ))}
    </div>
));

const SortableItem = SortableElement(({ value, disabled, propB }: { value: IJob; disabled: boolean; propB: any }) => (
    <Job job={value} key={value.get('jobId')} sortable={!disabled} />
));

private isJobSortable(job: IJob) {
    const status = job.get('status');
    return job.get('enqueued') && (status === 'idle' || status === 'error' || status === 'finished');
}

private handleQueueOrderChange({ newIndex, oldIndex }) {
    console.log(newIndex, oldIndex);
}

cpwinn avatar Sep 18 '19 16:09 cpwinn

is there a specific reason why the code is not protected against this case, and it is protected in the unmount?

      // Remove the helper from the DOM
      this.helper.parentNode.removeChild(this.helper);

versus:

      if (this.helper && this.helper.parentNode) {
        this.helper.parentNode.removeChild(this.helper);
      }

do you accept a PR to protect by this check in both cases?

bartvde avatar Jan 31 '20 14:01 bartvde

I also have this problem which is very annoying:

	const onSortStart = (): void => {
		console.log('%c sort started!', 'color: green;');
		setIsReorderingColumns((prevState) => !prevState);
	};

Uncaught TypeError: Cannot read property 'removeChild' of null

whenmoon avatar Aug 04 '20 09:08 whenmoon

I just had these same issues. It was caused by my SortableContainer and SortableElement being assigned inside of the render function. Meaning each time I set the state it would re-render and create a new instance of SortableContainer and SortableElement. That would divorce the old SortableElement from the DOM and cause the issues.

So the solution for me was to assign SortableContainer and SortableElement to variables outside of render() and reference those on render. Also, @rectangletangle is correct, updateBeforeSortStart should be used to set state rather that onSortStart.

Thanks, it solved my problem perfectly!

YangChunliang avatar Jan 12 '21 07:01 YangChunliang

I just had these same issues. It was caused by my SortableContainer and SortableElement being assigned inside of the render function. Meaning each time I set the state it would re-render and create a new instance of SortableContainer and SortableElement. That would divorce the old SortableElement from the DOM and cause the issues.

So the solution for me was to assign SortableContainer and SortableElement to variables outside of render() and reference those on render. Also, @rectangletangle is correct, updateBeforeSortStart should be used to set state rather that onSortStart.

It also solved my problem! Thank you 🙌

ubinatus avatar Apr 28 '21 03:04 ubinatus

I am having this problem with my onSortEnd call. I have SortableContainer and SortableElement outside of the render function as suggested above. I suppose I will fork the code and add a guard around the offending line as @bartvde suggested.

andrewluetgers avatar Feb 02 '22 19:02 andrewluetgers