创建新块 + 复制时不可变/Draftjs 错误“block.getKey 不是函数”

Posted

技术标签:

【中文标题】创建新块 + 复制时不可变/Draftjs 错误“block.getKey 不是函数”【英文标题】:Immutable / Draftjs Error 'block.getKey is not a function' when creating new block + reproduction 【发布时间】:2021-01-06 12:19:57 【问题描述】:

当我从 Immutable OrderedMap 到 Array 创建新的 contentState 时,即使提供了密钥,我也会从 Draftjs 获得 block.getKey is not a function...

我在 draftjs github 上发现了一个帖子,暗示这可能是一个错误,但它是从 2016 年开始的, 想知道是否有人有他们可以建议的解决方案或解决方法...

这是一个codeandbox复制的链接 https://codesandbox.io/s/blockgetkey-error-reproduction-h75mf?file=/src/index.js

import React from "react";
import ReactDOM from "react-dom";
import 
  List as ImmutableList,
  Repeat as ImmutableRepeat,
  Map as ImmutableMap,
  OrderedMap
 from "immutable";
import 
  Editor,
  EditorState,
  ContentBlock,
  ContentState,
  genKey,
  CharacterMetadata
 from "draft-js";
function MyEditor() 
  const [editorState, setEditorState] = React.useState(
    EditorState.createEmpty()
  );
  const editor = React.useRef(null);
  function focusEditor() 
    editor.current.focus();
  
  React.useEffect(() => 
    focusEditor();
  , []);
  return (
    <div onClick=focusEditor>
      <Editor
        ref=editor
        editorState=editorState
        onChange=(editorState) => setEditorState(editorState)
      />
      <button
        onClick=() => 
          // const newBlockMap = contentState.getBlockMap().set(newBlock.key, newBlock)
          const charData = CharacterMetadata.create();
          const text1 = "This was the test value";
          const contentState = editorState.getCurrentContent();
          const blockMap = contentState.getBlockMap();
          const newBlock = new ContentBlock(
            key: genKey(),
            type: "Img",
            text: text1,
            characterList: ImmutableList(
              ImmutableRepeat(charData, text1.length)
            ),
            data: ImmutableMap( content: "foo bear" )
          );

          const insertBefore = OrderedMap().withMutations((r) => 
            blockMap.forEach((k, v) => 
              console.log("k  ", k);
              console.log("v  ", v);
              if (3 === k) 
                r.set(newBlock.key, newBlock);
              
              r.set(k, v);
            );
          );

          let newcontentState = ContentState.createFromBlockArray(
            insertBefore.toArray()
          ).set("selectionAfter", contentState.getSelectionAfter());

          const newEditorState = EditorState.push(
            editorState,
            newcontentState,
            "insert-fragment"
          );

          setEditorState(
            ...editorState,
            editorState: newEditorState
          );
        
      >
        Add New Block
      </button>
    </div>
  );


function App() 
  return (
    <div>
      <h3>Test</h3>
      <MyEditor />
    </div>
  );

ReactDOM.render(<App />, document.getElementById("root"));

【问题讨论】:

【参考方案1】:

当我自己安装 immutable 并更新到 4.0 时,这开始发生

当我删除它并让 Draft-js 安装版本“3.7.6”时工作

【讨论】:

【参考方案2】:

我已经解决了这个问题,我会把我的工作代码留在这里,希望它可以帮助别人,

我正在使用 Immutebale 突变来尝试创建一个新的 BlockMap,但它似乎没有以 Draftjs 可以理解的方式构建。我没有使用循环,而是使用blockMap.toSeq().takeUntil((v)blockMap.toSeq().skipUntil((v) 来拆分当前时钟状态,添加新块并重新组装它。

我还将contnetState.createFromArray() 更改为contnetState.merge(),这样更干净!因为它允许您合并不可变的 Map 对象而无需转换。

                    e.preventDefault();
                    e.stopPropagation();

                    const getCurrentBlock = () => 
                        const selectionState = editorState.getSelection();
                        const contentState = editorState.getCurrentContent();
                        const block = contentState.getBlockForKey(selectionState.getStartKey());
                        return block;
                    ;

                    let pivotBlockKey = getCurrentBlock().key
                    const contnetState = editorState.getCurrentContent();
                    const blockMap = contnetState.getBlockMap();
                    const block = blockMap.get(pivotBlockKey);
                    const blocksBefore = blockMap.toSeq().takeUntil((v) => (v === block));
                    const blocksAfter = blockMap.toSeq().skipUntil((v) => (v === block)).rest();

                    const charData = CharacterMetadata.create()
                    const text1 = "This was the test value"
                    const newBlockKey = genKey()
                    const newBlock = new ContentBlock(
                        key: newBlockKey,
                        type: "header-one",
                        text: text1,
                        characterList: ImmutableList(ImmutableRepeat(charData, text1.length)),
                        data: ImmutableMap( content: "foo bear" )
                    )

                    const newBlockMap = blocksBefore.concat(
                        [[pivotBlockKey, block], [newBlockKey, newBlock]],
                        blocksAfter
                    ).toOrderedMap();

                    let newContnetState = contnetState.merge(
                        blockMap: newBlockMap,
                        selectionBefore: contentState.getSelectionBefore()
                    )
                    
                    const newEditorState = EditorState.push(
                        editorState, 
                        newContnetState,
                        'insert-fragment'
                    );
                    
                    setState( 
                        ...state,
                        editorState: newEditorState,
                    );

【讨论】:

以上是关于创建新块 + 复制时不可变/Draftjs 错误“block.getKey 不是函数”的主要内容,如果未能解决你的问题,请参考以下文章

如何阻止 DraftJS 光标跳到文本的开头?

DraftJs:不变违规:使用 convertToRaw 时块不是 BlockNode

如何在java中从可变对象创建不可变对象? [复制]

使用 URI 复制时不支持文件名中的特殊字符

如何从 localStorage 读取 DraftJS 状态?

Draftjs中的选择感知keyBindingFn