draft-js Cannot read property 'getIn' of undefined ( getUpdatedSelectionState )
Asked Answered
S

3

21

I have this error with draft-js with draft-js-plugins-editor

STRANGE BEHAVIOR: it only happens, when I refocus to first line of editor after writing, when trying to set for eg. the header of first line to H1 it changes previous focused line

ERROR: Uncaught TypeError: Cannot read property 'getIn' of undefined

FULL ERROR:

Uncaught TypeError: Cannot read property 'getIn' of undefined
    at getUpdatedSelectionState (getUpdatedSelectionState.js?a009439:34)
    at getDraftEditorSelectionWithNodes (getDraftEditorSelectionWithNodes.js?a009439:37)
    at getDraftEditorSelection (getDraftEditorSelection.js?a7f8e9b:35)
    at editOnSelect (editOnSelect.js?a7f8e9b:32)
    at DraftEditor.react.js?f8ee1ff:148
    at HTMLUnknownElement.callCallback (react-dom.development.js?5f39724:542)
    at Object.invokeGuardedCallbackDev (react-dom.development.js?5f39724:581)
    at Object.invokeGuardedCallback (react-dom.development.js?5f39724:438)
    at Object.invokeGuardedCallbackAndCatchFirstError (react-dom.development.js?5f39724:452)
    at executeDispatch (react-dom.development.js?5f39724:836)

This is my component:

/* eslint-disable react/no-multi-comp */
import React, {Component} from 'react';
import sv from '../../config/styleVariables'

import Editor from 'draft-js-plugins-editor';
import {EditorState,convertToRaw} from 'draft-js'
import createToolbarPlugin from 'draft-js-static-toolbar-plugin';
import {
  ItalicButton,
  BoldButton,
  UnderlineButton,
  HeadlineOneButton,
  HeadlineTwoButton,
  HeadlineThreeButton,
  UnorderedListButton,
  OrderedListButton,
  BlockquoteButton,
} from 'draft-js-buttons'




export default class TextArea extends Component {


  constructor(props){
    super(props)

    this.state = {
      editorState: EditorState.createEmpty(),
    }

    const toolbarPlugin = createToolbarPlugin({
      structure: [
        BoldButton,
        ItalicButton,
        UnderlineButton,
        HeadlineOneButton, ,
        HeadlineTwoButton,
        HeadlineThreeButton,
        UnorderedListButton,
        OrderedListButton,
        // BlockquoteButton,
      ]
    })

    const { Toolbar } = toolbarPlugin;
    this.Toolbar = Toolbar
    this.plugins = [toolbarPlugin];

  }

  onChange(editorState){
    this.setState({
      editorState,
    })
    this.props.update(JSON.stringify(convertToRaw(editorState.getCurrentContent())))
  }

  focus(){
    this.editor.focus();
  }

  render() {
    const {Toolbar, plugins} = this
    const {name} = this.props
    return (
      <div className="TextArea">
        {/*language=SCSS*/}
        <style jsx global>{`
          .TextArea .headlineButtonWrapper {
            display: inline-block;
          }
          .TextArea {
            background: ${sv.white};
          }
          .TextArea > div>div:first-child {
            display: flex;
            padding: 0 0 .25em 0;
            border-bottom: 1px solid ${sv.border};
          }
          .TextArea > div>div:first-child>div button{
            background: transparent;
            cursor: pointer;
            border: none;
            display: flex;
            align-items: center;
            justify-content: center;
            width: 3em;
            height: 2.5em;
            font-size: .8em;
            margin-right: .2em;
          }
          .TextArea > div>div:first-child>div button:hover {
            background: ${sv.extraLight};
            color: ${sv.primary};
          }
          .TextArea .DraftEditor-root {
            padding: 0 .5em;
            cursor: text;
          }

          .TextArea .headlineButton {
            background: #fbfbfb;
            color: #888;
            font-size: 18px;
            border: 0;
            padding-top: 5px;
            vertical-align: bottom;
            height: 34px;
            width: 36px;
          }

          .TextArea .headlineButton:hover,
          .TextArea .headlineButton:focus {
            background: #f3f3f3;
          }
        `}
        </style>
        <div onClick={this.focus.bind(this)}>
          <Toolbar key={name} />
          <Editor
            editorState={this.state.editorState}
            onChange={this.onChange.bind(this)}
            plugins={plugins}
            ref={(element) => {
              this.editor = element
            }}
          />
        </div>
      </div>
    );
  }
}

My component looks like this:

my component

Shanan answered 12/1, 2018 at 16:19 Comment(1)
Are you using the last version of immutable in your project?Viperish
S
1

I meet the same problem. It looks like because call editorState.getBlockTree(anchorBlockKey).getIn(...) in getUpdatedSelectionState.js the editorState.getBlockTree(anchorBlockKey) is undefined whenever the block type is unstyled.

I have no idea how to fix it, so make a work around solution like this:

const headerOne = '<h1>Title</h1>';
const blocksFromHTML = convertFromHTML(headerOne);
const state = ContentState.createFromBlockArray(
    blocksFromHTML.contentBlocks,
    blocksFromHTML.entityMap
);
this.state = {
    editorState: EditorState.createWithContent(state)
}

But there will be another problem when you press enter new line will be H1 either.

Sarcastic answered 19/7, 2018 at 7:11 Comment(0)
E
1

I'm using next js and I faced the same issue and according to this PR, where they says that it may be a SSR problem, I was able to solve my problem by importing my editor dynamically.

const RichTextEditor = dynamic(
  () =>
    import("@/components/RichTextEditor").then(
      (mod) => mod.RichTextEditor
    ),
  {    ssr: false   }
);
Entomology answered 24/9, 2023 at 10:28 Comment(1)
You're my life saver! Thank youuuIodide
R
0

Here they say that the component is rendering differently between the server and the client, and this causes the issue: https://github.com/facebookarchive/draft-js/issues/2332

This solution seems to work for me. It forces the component to render only on the client. Which for me works because I don't need any SEO from the text editor.

"use client";

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

function Composer() {
  const [editorState, setEditorState] = useState<EditorState>();

  useEffect(() => {
    setEditorState(EditorState.createEmpty());
  }, []);

  return (
    <div>
      {editorState && (
        <Editor editorState={editorState} onChange={setEditorState} />
      )}
    </div>
  );
}

export default Composer;
Rampageous answered 11/8, 2023 at 16:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.