Draft-js: Uncaught TypeError: Cannot read property 'getIn' of undefined

Created on 25 Feb 2020  路  13Comments  路  Source: facebook/draft-js

Do you want to request a feature or report a bug?

Bug

What is the current behavior?

When there are two DraftJS instances on the page, and you start the selection in one and finish it in the second, the editor crashes with the following error:

Uncaught TypeError: Cannot read property 'getIn' of undefined
    at getUpdatedSelectionState (Draft.js:4829)
    at getDraftEditorSelectionWithNodes (Draft.js:4636)
    at getDraftEditorSelection (Draft.js:4590)
    at editOnSelect (Draft.js:4484)

How to reproduce:

It seems that the editor detects the target is a DraftJS based on its markup structure but doesn't check it is its own instance. Therefore the selection handling assumes the existence of the underlying data, but the data is not found in current instance and it fails.

What is the expected behavior?

The editor does not throw an error, and updates the selection towards its end/start.

Which versions of Draft.js, and which browser / OS are affected by this issue? Did this work in previous versions of Draft.js?

Chrome Version 80.0.3987.116 (Official Build) (64-bit)
DraftJS 0.11.4 (latest)

Most helpful comment

We are only doing client side rendering and getting this issue. Is there a fix?

All 13 comments

I've got the same error when I try to change a checkbox using medium-draft

And Sentry reports it in the file ../node_modules/draft-js/lib/editOnInput.js

https://github.com/facebook/draft-js/blob/792bd3abe9b2c8735e2917af30b3dc9b0055e3ab/src/component/handlers/edit/editOnInput.js#L106-L108

Chrome Version 80.0.3987.132 (Official Build) (64-bit)
Firefox Version 74.0 (64-bit)
DraftJS 0.11.4 (latest)

And maybe it's related to issue #2204 because sometimes throw the error Cannot read property 'nodeType' of null in these lines

https://github.com/facebook/draft-js/blob/792bd3abe9b2c8735e2917af30b3dc9b0055e3ab/src/component/handlers/edit/editOnInput.js#L71-L73

馃

Merged https://github.com/facebook/draft-js/pull/2330 which should deal with Cannot read property 'nodeType' of null. I expect we will still see this getIn error, but FYI (:

@kenticomartinh had a look, the exception you're seeing has been fixed already, the changed have just not been published to npm. They'll be there once 0.11.5 comes around:

https://github.com/facebook/draft-js/blob/a9fcbb201de604e040dacb66e67407989a0e2d9b/src/component/selection/getUpdatedSelectionState.js#L40-L46

@lavaldi, the issue you're seeing in editOnInput.js seems to be unrelated. Could you open another issue and just copy your comment there, to track it separately? Put a link to this issue for reference too.

@lavaldi, the issue you're seeing in editOnInput.js seems to be unrelated. Could you open another issue and just copy your comment there, to track it separately? Put a link to this issue for reference too.

Sure @mrkev! Done it!

I'm not able to do any editing without receiving this error. Is there any workaround for this until 0.11.5 is published?

UPDATE 1 After downloading 0.11.5 I'm still seeing this issue. The error manifests in different ways on different browsers, but the root of it seems to be "Invalid Selection State". It appears to be some kind of incompatibility with NextJS: https://codesandbox.io/s/reverent-fire-bvogb

UPDATE 2 It appears the cause of this issue is the server rendering one thing with one selection state key, and then the client rendering a with a different key. See https://github.com/facebook/draft-js/issues/1199#issuecomment-331677160

@davidgolden Did you find a solution regarding using DraftJS with NextJS? I'm still getting this issue and would have to consider moving to a different solution if this is persistent.

@bathientran I did, the trick is to pass in a static key so that it's rendered the same on the server and the client, this is what's working for me (I'm also using markdown-draft-js):

export default function DraftEditor(props) {
    const editorRef = useRef(null);

    const markdown = useRef(markdownToDraft(props.value));
    markdown.current.blocks = markdown.current.blocks.map((b, i) => ({...b, key: `foo-${i}`}));
    const [editorState, setEditorState] = useState(EditorState.createWithContent(convertFromRaw(markdown.current)));

    function handleChange(state) {
        setEditorState(state);
        props.handleChange(draftToMarkdown(convertToRaw(state.getCurrentContent())));
    }

    return <Editor editorState={editorState} onChange={handleChange} ref={editorRef}/>
}

We are only doing client side rendering and getting this issue. Is there a fix?

Got the same error and warning but I'm using 0.11.7.
Only rendered in client and customize some element in editor.

UPDATE
Seems like adding userSelect="none" and contentEditable={false} to custom element can fix it.

Sep-27-2020 17-12-58

Thank you. For me this worked with next.js

import React, { Component } from 'react'
import { Editor, EditorState } from 'draft-js'
class App extends Component {
    constructor(props) {
        super(props)
        this.state = {
            editorState: EditorState.createEmpty()
        }
    }


    onChange(editorState) {
        this.setState({
            editorState: editorState
        })
    }

    render() {
        return (
            <div className="blog-editor">
                <Editor editorState={this.state.editorState} onChange={this.onChange.bind(this)} userSelect="none" contentEditable={false} />
            </div>
        )
    }
}
export default App

Follow the workaround in this Example will solve this issue

https://github.com/facebook/draft-js/blob/master/examples/draft-0-10-0/universal/editor.js

Just simply create an empty content instead to use the function createEmpty

Here is my component is working with the react-hook-form

import React, { useEffect } from "react";
import { Editor, EditorState, ContentState, convertFromRaw } from "draft-js";
import "draft-js/dist/Draft.css";

export { EditorState, ContentState };

interface PropTypes {
  name?: string;
  value?: string;
  onChange?: Function;
}

// Trick to fix issue with NextJS https://github.com/facebook/draft-js/blob/master/examples/draft-0-10-0/universal/editor.js
const emptyContentState = convertFromRaw({
  entityMap: {},
  blocks: [
    {
      text: "",
      key: "foo",
      type: "unstyled",
      entityRanges: [],
    },
  ],
});

function RichTextEditor({ name, value, onChange }: PropTypes) {
  const [editorState, setEditorState] = React.useState(
    EditorState.createWithContent(emptyContentState)
  );

  useEffect(() => {
    setEditorState(
      EditorState.createWithContent(ContentState.createFromText(value))
    );
  }, []);

  return (
    <Editor
      editorKey={name}
      editorState={editorState}
      onChange={(editorState) => {
        setEditorState(editorState);

        onChange(editorState.getCurrentContent().getPlainText());
      }}
      userSelect="none"
      contentEditable={false}
    />
  );
}

export default RichTextEditor;

<Controller
        as={RichTextEditor}
        name="description"
        control={control}
        defaultValue=""
      />

Follow the workaround in this Example will solve this issue

https://github.com/facebook/draft-js/blob/master/examples/draft-0-10-0/universal/editor.js

Just simply create an empty content instead to use the function createEmpty

Here is my component is working with the react-hook-form

import React, { useEffect } from "react";
import { Editor, EditorState, ContentState, convertFromRaw } from "draft-js";
import "draft-js/dist/Draft.css";

export { EditorState, ContentState };

interface PropTypes {
  name?: string;
  value?: string;
  onChange?: Function;
}

// Trick to fix issue with NextJS https://github.com/facebook/draft-js/blob/master/examples/draft-0-10-0/universal/editor.js
const emptyContentState = convertFromRaw({
  entityMap: {},
  blocks: [
    {
      text: "",
      key: "foo",
      type: "unstyled",
      entityRanges: [],
    },
  ],
});

function RichTextEditor({ name, value, onChange }: PropTypes) {
  const [editorState, setEditorState] = React.useState(
    EditorState.createWithContent(emptyContentState)
  );

  useEffect(() => {
    setEditorState(
      EditorState.createWithContent(ContentState.createFromText(value))
    );
  }, []);

  return (
    <Editor
      editorKey={name}
      editorState={editorState}
      onChange={(editorState) => {
        setEditorState(editorState);

        onChange(editorState.getCurrentContent().getPlainText());
      }}
      userSelect="none"
      contentEditable={false}
    />
  );
}

export default RichTextEditor;
<Controller
        as={RichTextEditor}
        name="description"
        control={control}
        defaultValue=""
      />

thank you very much my friend, i spent a lot of time looking for this solution.

Was this page helpful?
0 / 5 - 0 ratings