首页 > 解决方案 > 创建新块 + 复制时不可变/Draftjs 错误“block.getKey 不是函数”

问题描述

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

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

这是一个codesandbox复制的链接 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"));

标签: javascriptreactjsimmutable.jsdraftjs

解决方案


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

我正在使用 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,
                    });

推荐阅读