在 DraftJS 中执行异步装饰?

Perform Asynchronous Decorations in DraftJS?

我正在尝试在所见即所得编辑器中执行实时命名实体识别突出显示,这需要我在每次击键之间向我的后端发出请求。

在 ProseMirror 上花了大约一个星期后,我放弃了它并决定尝试 DraftJS。我搜索了存储库和文档,但没有找到任何使用 Decorations 的异步示例。 (有一些 Entities 的示例,但它们似乎不适合我的问题。)

这是我要解决的 stripped down Codepen

归结为我想做这样的事情:

const handleStrategy = (contentBlock, callback, contentState) => {
  const text = contentBlock.getText();
  let matchArr, start;
  while ((matchArr = properNouns.exec(text)) !== null) {
    start = matchArr.index;
    setTimeout(() => {
//    THROWS ERROR: Cannot read property '0' of null
      callback(start, start + matchArr[0].length);
    }, 200) // to simulate API request
  }
};

我希望它在超时解决后异步调用回调,但 matchArr 是空的,这让我很困惑。

感谢任何帮助!

好的,一个可能的解决方案,一个例子,简单的版本(可能不是 100% 固体):

  1. 写一个函数获取编辑器的字符串,将其发送到服务器,并解析从服务器获取的数据,你需要弄清楚发送整个编辑器字符串还是只发送一个单词
getServerResult = data => new Promise((resolve, reject) => {
      ...

      fetch(link, {
        method: 'POST',
        headers: {
          ...
        },
        // figure what to send here
        body: this.state.editorState.getCurrentContent().getPlainText(),
      })
        .then(res => resolve(res))
        .catch(reject);
    });
  1. 确定何时调用 getServerResult 函数(即何时将字符串发送到服务器并获取实体数据),据我从您的评论中了解到,当用户按下空格键时,将之前的单词发送到服务器,这可以完成通过 draftjs Key Bindings or react SyntheticEvent。您将需要处理用户连续多次按下空格键的情况。
function myKeyBindingFn(e: SyntheticKeyboardEvent): string {
  if (e.keyCode === 32) {
    return 'send-server';
  }
  return getDefaultKeyBinding(e);
}

async handleKeyCommand(command: string): DraftHandleValue {
  if (command === 'send-server') {
    // you need to manually add a space char to the editorState
    // and get result from server

    ...

    // entity data get from server
    const result = await getServerResult()

    return 'handled';
  }
  return 'not-handled';
}
  1. 使用 ContentState 添加从服务器获取的实体数据到特定单词。createEntity()
  async handleKeyCommand(command: string): DraftHandleValue {
    if (command === 'send-server') {
      // you need to manually add a space char to the editorState
      // and get result from server

      ...

      // entity data get from server
      const result = await getServerResult()

      const newContentState = ContentState.createEntity(
        type: 'string',
        mutability: ...
        data: result
      )

      const entityKey = contentStateWithEntity.getLastCreatedEntityKey();

      // you need to figure out the selectionState, selectionState mean add 
      // the entity data to where

      const contentStateWithEntity = Modifier.applyEntity(
         newContentState,
         selectionState,
         entityKey
      );

      // create a new EditorState and use this.setState()
      const newEditorState = EditorState.push(
        ...
        contentState: contentStateWithEntity
      )

      this.setState({
        editorState: newEditorState
      })

      return 'handled';
    }
    return 'not-handled';
  }
  1. 创建不同的装饰器来查找具有特定实体数据的单词,以及 return 不同的样式或您需要的任何内容 return
...
const compositeDecorator = new CompositeDecorator([
  strategy: findSubjStrategy,
  component: HandleSubjSpan,
])
function findSubjStrategy(contentBlock, callback, contentState) {
  // search whole editor content find words with subj entity data
  // if the word's entity data === 'Subj'
  // pass the start index & end index of the word to callback

  ...
  if(...) {
   ... 
   callback(startIndex, endIndex);
  }
}

// this function handle what if findSubjStrategy() find any word with subj
// entity data
const HandleSubjSpan = (props) => {

  // if the word with subj entity data, it font color become red
  return <span {...props} style={{ color: 'red' }}>{props.children}</span>;
};